From f6cdc69aa4e2072917686e050b416bcd966afc8d Mon Sep 17 00:00:00 2001 From: Misha Behersky Date: Mon, 29 Jul 2024 14:16:08 +0300 Subject: [PATCH] Update clean command (#33) --- CHANGELOG.md | 23 ++++++- USAGE.md | 63 ++++++++++++------- examples/show_details.py | 1 + hapless/cli.py | 52 +++++++++++----- hapless/hap.py | 33 +++++----- hapless/main.py | 14 ++--- poetry.lock | 128 +-------------------------------------- pyproject.toml | 3 +- tests/test_cli.py | 11 +++- tests/test_hap.py | 2 +- 10 files changed, 138 insertions(+), 192 deletions(-) mode change 100644 => 100755 examples/show_details.py diff --git a/CHANGELOG.md b/CHANGELOG.md index ecfd8c7..be50add 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,9 +17,24 @@ Available sections are: ## [Unreleased] + +## [v0.4.0] + ### Added -- Allow to use current active shell to run commands instead of the default one. +- New command `hap cleanall` to delete all finished haps (both successful and failed) + + +### Changed + +- Command `hap clean` now accepts `--all` parameter to cleanup both successful and failed haps from the list + + +## [v0.3.0] + +### Fixed + +- Fix [issue](https://github.com/bmwant/hapless/issues/30) when displaying runtime for the corrupted hap ## [v0.2.2] @@ -121,7 +136,11 @@ Available sections are: - Initial release. -[Unreleased]: https://github.com/bmwant/hapless/compare/v0.2.0...HEAD +[Unreleased]: https://github.com/bmwant/hapless/compare/v0.4.0...HEAD + +[v0.4.0]: https://github.com/bmwant/hapless/compare/v0.3.0...v0.4.0 + +[v0.3.0]: https://github.com/bmwant/hapless/compare/v0.2.0...v0.3.0 [v0.2.0]: https://github.com/bmwant/hapless/compare/v0.1.10...v0.2.0 diff --git a/USAGE.md b/USAGE.md index 17c2a1c..2f0a697 100644 --- a/USAGE.md +++ b/USAGE.md @@ -9,22 +9,32 @@ ➡️ Run a simple script ```bash -$ hap run ./examples/script.sh -$ hap run python ./examples/fast.py +hap run ./examples/script.sh +hap run python ./examples/fast.py ``` ➡️ Run script accepting arguments ```bash -$ hap run -- python ./examples/show_details.py -v --name details --count=5 +hap run -- python ./examples/show_details.py -v --name details --count=5 ``` Use `--` delimiter in order to separate target script and its arguments. Otherwise arguments will be interpreted as a keys for `hap` executable. +> NOTE: as of version `0.4.0` specifying double dash is optional and required only if parameters for your target command match parameters of `hap run` command itself + +```bash +# wouldn't work, as run has its own `--help` option +hap run python --help + +# will work as expected without `--` delimiter +hap run ./examples/show_details.py --flag --param=value +``` + ➡️ Check script for early failures right after launch ```bash -$ hap run --check python ./examples/fail_fast.py +hap run --check python ./examples/fail_fast.py ``` ### ✏️ Checking status @@ -32,28 +42,28 @@ $ hap run --check python ./examples/fail_fast.py ➡️ Show summary for all haps ```bash -$ hap +hap # or -$ hap status # equivalent -$ hap show # same as above +hap status # equivalent +hap show # same as above ``` ➡️ Check status of the specific hap ```bash -$ hap show [hap-alias] +hap show [hap-alias] # or -$ hap status [hap-alias] +hap status [hap-alias] ``` ➡️ Show detailed status for the hap (including environment variables) ```bash -$ hap show -v [hap-alias] -$ hap show --verbose [hap-alias] # same as above +hap show -v [hap-alias] +hap show --verbose [hap-alias] # same as above # or -$ hap status -v [hap-alias] -$ hap status --verbose [hap-alias] # same as above +hap status -v [hap-alias] +hap status --verbose [hap-alias] # same as above ``` ### ✏️ Checking logs @@ -61,15 +71,15 @@ $ hap status --verbose [hap-alias] # same as above ➡️ Print process logs to the console ```bash -$ hap logs [hap-alias] +hap logs [hap-alias] ``` ➡️ Stream logs continuously to the console ```bash -$ hap logs -f [hap-alias] +hap logs -f [hap-alias] # or -$ hap logs --follow [hap-alias] +hap logs --follow [hap-alias] ``` ### ✏️ Other commands @@ -77,20 +87,31 @@ $ hap logs --follow [hap-alias] ➡️ Suspend (pause) a hap. Sends `SIGSTOP` signal to the process ```bash -$ hap pause [hap-alias] +hap pause [hap-alias] # or -$ hap suspend [hap-alias] +hap suspend [hap-alias] ``` ➡️ Resume paused hap. Sends `SIGCONT` signal to the suspended process ```bash -$ hap resume [hap-alias] +hap resume [hap-alias] ``` ➡️ Send specific signal to the process by its code ```bash -$ hap signal [hap-alias] 9 # sends SIGKILL -$ hap signal [hap-alias] 15 # sends SIGTERM +hap signal [hap-alias] 9 # sends SIGKILL +hap signal [hap-alias] 15 # sends SIGTERM +``` + +- Remove haps from the list. Without any parameters removes only successfully finished haps (with `0` return code). Provide `--all` flag to remove failed haps as well. Used to make list more concise in case you have a lot of things running at once and you are not interested in results/error logs of completed ones. + +```bash +hap clean + +# Remove all finished haps (both successful and failed) +hap clean --all +# Same as above +hap cleanall ``` diff --git a/examples/show_details.py b/examples/show_details.py old mode 100644 new mode 100755 index 56a8f68..ebc9726 --- a/examples/show_details.py +++ b/examples/show_details.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python3 import os import sys diff --git a/hapless/cli.py b/hapless/cli.py index d7f278d..ef22000 100644 --- a/hapless/cli.py +++ b/hapless/cli.py @@ -38,14 +38,14 @@ def cli(ctx, verbose): _status(None, verbose=verbose) -@cli.command(short_help="Display information about haps") +@cli.command(short_help="Display information about haps.") @click.argument("hap_alias", metavar="hap", required=False) @click.option("-v", "--verbose", is_flag=True, default=False) def status(hap_alias, verbose): _status(hap_alias, verbose) -@cli.command(short_help="Same as a status") +@cli.command(short_help="Same as a status.") @click.argument("hap_alias", metavar="hap", required=False) @click.option("-v", "--verbose", is_flag=True, default=False) def show(hap_alias, verbose): @@ -61,7 +61,7 @@ def _status(hap_alias: Optional[str] = None, verbose: bool = False): hapless.stats(haps, verbose=verbose) -@cli.command(short_help="Output logs for a hap") +@cli.command(short_help="Output logs for a hap.") @click.argument("hap_alias", metavar="hap") @click.option("-f", "--follow", is_flag=True, default=False) @click.option("-e", "--stderr", is_flag=True, default=False) @@ -70,16 +70,40 @@ def logs(hap_alias, follow, stderr): hapless.logs(hap, stderr=stderr, follow=follow) -@cli.command(short_help="Remove finished haps") -@click.option("--skip-failed", is_flag=True, default=False) -def clean(skip_failed): - hapless.clean(skip_failed) +@cli.command(short_help="Remove successfully completed haps.") +@click.option( + "-a", + "--all", + "clean_all", + is_flag=True, + default=False, + help="Include failed haps for the removal.", +) +def clean(clean_all): + hapless.clean(clean_all=clean_all) -@cli.command(short_help="Execute background command as a hap") +@cli.command(short_help="Remove all finished haps, including failed ones.") +def cleanall(): + hapless.clean(clean_all=True) + + +@cli.command( + short_help="Execute background command as a hap.", + context_settings=dict( + ignore_unknown_options=True, + ), +) @click.argument("cmd", nargs=-1) -@click.option("-n", "--name") -@click.option("--check", is_flag=True, default=False) +@click.option( + "-n", "--name", help="Provide your own alias for the hap instead of a default one." +) +@click.option( + "--check", + is_flag=True, + default=False, + help="Verify command launched does not fail immediately.", +) def run(cmd, name, check): hap = hapless.get_hap(name) if hap is not None: @@ -101,21 +125,21 @@ def run(cmd, name, check): hapless.run(cmd_escaped, name=name, check=check) -@cli.command(short_help="Pause a specific hap") +@cli.command(short_help="Pause a specific hap.") @click.argument("hap_alias", metavar="hap") def pause(hap_alias): hap = get_or_exit(hap_alias) hapless.pause_hap(hap) -@cli.command(short_help="Resume execution of a paused hap") +@cli.command(short_help="Resume execution of a paused hap.") @click.argument("hap_alias", metavar="hap") def resume(hap_alias): hap = get_or_exit(hap_alias) hapless.resume_hap(hap) -@cli.command(short_help="Terminate a specific hap / all haps") +@cli.command(short_help="Terminate a specific hap / all haps.") @click.argument("hap_alias", metavar="hap", required=False) @click.option("-a", "--all", "killall", is_flag=True, default=False) def kill(hap_alias, killall): @@ -135,7 +159,7 @@ def kill(hap_alias, killall): hapless.kill([hap]) -@cli.command(short_help="Send an arbitrary signal to a hap") +@cli.command(short_help="Send an arbitrary signal to a hap.") @click.argument("hap_alias", metavar="hap") @click.argument("signal", callback=validate_signal, metavar="signal-code") def signal(hap_alias, signal): diff --git a/hapless/hap.py b/hapless/hap.py index 5aeb3c1..7a98edc 100644 --- a/hapless/hap.py +++ b/hapless/hap.py @@ -4,6 +4,7 @@ import string import time from datetime import datetime +from enum import Enum from pathlib import Path from typing import Dict, Optional @@ -19,14 +20,15 @@ from hapless import config from hapless.utils import allow_missing, get_mtime, logger -""" -active -* paused -* running -finished -* finished(failed) non-zero rc -* finished(success) zero rc -""" + +# TODO: add unbound status for the hap without associated pid +class Status(str, Enum): + # Active statuses + PAUSED = "paused" + RUNNING = "running" + # Finished statuses + FAILED = "failed" + SUCCESS = "success" class Hap(object): @@ -95,7 +97,7 @@ def _set_env(self): with open(self._env_file, "w") as env_file: env_file.write(json.dumps(environ)) - def attach(self, pid: int): + def bind(self, pid: int): """ Associate hap object with existing process by pid """ @@ -103,7 +105,7 @@ def attach(self, pid: int): self._set_pid(pid) self._set_env() except (RuntimeError, psutil.AccessDenied) as e: - logger.error(f"Cannot attached due to {e}") + logger.error(f"Cannot bind due to {e}") @staticmethod def get_random_name(length: int = 6): @@ -115,19 +117,18 @@ def get_random_name(length: int = 6): ) # TODO: add extended status to show panel proc.status() - # TODO: return enum entries instead @property - def status(self) -> str: + def status(self) -> Status: proc = self.proc if proc is not None: if proc.status() == psutil.STATUS_STOPPED: - return "paused" - return "running" + return Status.PAUSED + return Status.RUNNING if self.rc != 0: - return "failed" + return Status.FAILED - return "success" + return Status.SUCCESS @cached_property def proc(self): diff --git a/hapless/main.py b/hapless/main.py index 807b6c4..f729bd1 100644 --- a/hapless/main.py +++ b/hapless/main.py @@ -23,7 +23,7 @@ from rich.text import Text from hapless import config -from hapless.hap import Hap +from hapless.hap import Hap, Status from hapless.utils import kill_proc_tree, logger, wait_created console = Console(highlight=False) @@ -225,7 +225,7 @@ def run_hap(self, hap: Hap): pid = proc.pid logger.debug(f"Attaching hap {hap} to pid {pid}") - hap.attach(pid) + hap.bind(pid) retcode = proc.wait() @@ -287,11 +287,11 @@ def logs(self, hap: Hap, stderr: bool = False, follow: bool = False): else: return subprocess.run(["cat", filepath]) - def clean(self, skip_failed: bool = False): - def to_clean(hap): - if hap.rc is not None: - return hap.rc == 0 or not skip_failed - return False + def clean(self, clean_all: bool = False): + def to_clean(hap: Hap) -> bool: + return hap.status == Status.SUCCESS or ( + hap.status == Status.FAILED and clean_all + ) haps = list(filter(to_clean, self.get_haps())) for hap in haps: diff --git a/poetry.lock b/poetry.lock index 81090c5..0573efe 100644 --- a/poetry.lock +++ b/poetry.lock @@ -11,42 +11,6 @@ files = [ {file = "backports.cached_property-1.0.2-py3-none-any.whl", hash = "sha256:baeb28e1cd619a3c9ab8941431fe34e8490861fb998c6c4590693d50171db0cc"}, ] -[[package]] -name = "black" -version = "22.12.0" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.7" -files = [ - {file = "black-22.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d"}, - {file = "black-22.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351"}, - {file = "black-22.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f"}, - {file = "black-22.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:7412e75863aa5c5411886804678b7d083c7c28421210180d67dfd8cf1221e1f4"}, - {file = "black-22.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c116eed0efb9ff870ded8b62fe9f28dd61ef6e9ddd28d83d7d264a38417dcee2"}, - {file = "black-22.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1f58cbe16dfe8c12b7434e50ff889fa479072096d79f0a7f25e4ab8e94cd8350"}, - {file = "black-22.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d86c9f3db9b1bf6761244bc0b3572a546f5fe37917a044e02f3166d5aafa7d"}, - {file = "black-22.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:82d9fe8fee3401e02e79767016b4907820a7dc28d70d137eb397b92ef3cc5bfc"}, - {file = "black-22.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:101c69b23df9b44247bd88e1d7e90154336ac4992502d4197bdac35dd7ee3320"}, - {file = "black-22.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:559c7a1ba9a006226f09e4916060982fd27334ae1998e7a38b3f33a37f7a2148"}, - {file = "black-22.12.0-py3-none-any.whl", hash = "sha256:436cc9167dd28040ad90d3b404aec22cedf24a6e4d7de221bec2730ec0c97bcf"}, - {file = "black-22.12.0.tar.gz", hash = "sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -pathspec = ">=0.9.0" -platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} -typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} -typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - [[package]] name = "certifi" version = "2024.7.4" @@ -526,17 +490,6 @@ files = [ {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, ] -[[package]] -name = "mypy-extensions" -version = "1.0.0" -description = "Type system extensions for programs checked with the mypy type checker." -optional = false -python-versions = ">=3.5" -files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, -] - [[package]] name = "packaging" version = "24.0" @@ -548,35 +501,6 @@ files = [ {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, ] -[[package]] -name = "pathspec" -version = "0.11.2" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.7" -files = [ - {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, - {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, -] - -[[package]] -name = "platformdirs" -version = "4.0.0" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -optional = false -python-versions = ">=3.7" -files = [ - {file = "platformdirs-4.0.0-py3-none-any.whl", hash = "sha256:118c954d7e949b35437270383a3f2531e99dd93cf7ce4dc8340d3356d30f173b"}, - {file = "platformdirs-4.0.0.tar.gz", hash = "sha256:cb633b2bcf10c51af60beb0ab06d2f1d69064b43abf4c185ca6b28865f3f9731"}, -] - -[package.dependencies] -typing-extensions = {version = ">=4.7.1", markers = "python_version < \"3.8\""} - -[package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] - [[package]] name = "pluggy" version = "1.2.0" @@ -814,56 +738,6 @@ files = [ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] -[[package]] -name = "typed-ast" -version = "1.5.5" -description = "a fork of Python 2 and 3 ast modules with type comment support" -optional = false -python-versions = ">=3.6" -files = [ - {file = "typed_ast-1.5.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4bc1efe0ce3ffb74784e06460f01a223ac1f6ab31c6bc0376a21184bf5aabe3b"}, - {file = "typed_ast-1.5.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5f7a8c46a8b333f71abd61d7ab9255440d4a588f34a21f126bbfc95f6049e686"}, - {file = "typed_ast-1.5.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:597fc66b4162f959ee6a96b978c0435bd63791e31e4f410622d19f1686d5e769"}, - {file = "typed_ast-1.5.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d41b7a686ce653e06c2609075d397ebd5b969d821b9797d029fccd71fdec8e04"}, - {file = "typed_ast-1.5.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5fe83a9a44c4ce67c796a1b466c270c1272e176603d5e06f6afbc101a572859d"}, - {file = "typed_ast-1.5.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d5c0c112a74c0e5db2c75882a0adf3133adedcdbfd8cf7c9d6ed77365ab90a1d"}, - {file = "typed_ast-1.5.5-cp310-cp310-win_amd64.whl", hash = "sha256:e1a976ed4cc2d71bb073e1b2a250892a6e968ff02aa14c1f40eba4f365ffec02"}, - {file = "typed_ast-1.5.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c631da9710271cb67b08bd3f3813b7af7f4c69c319b75475436fcab8c3d21bee"}, - {file = "typed_ast-1.5.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b445c2abfecab89a932b20bd8261488d574591173d07827c1eda32c457358b18"}, - {file = "typed_ast-1.5.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc95ffaaab2be3b25eb938779e43f513e0e538a84dd14a5d844b8f2932593d88"}, - {file = "typed_ast-1.5.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61443214d9b4c660dcf4b5307f15c12cb30bdfe9588ce6158f4a005baeb167b2"}, - {file = "typed_ast-1.5.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6eb936d107e4d474940469e8ec5b380c9b329b5f08b78282d46baeebd3692dc9"}, - {file = "typed_ast-1.5.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e48bf27022897577d8479eaed64701ecaf0467182448bd95759883300ca818c8"}, - {file = "typed_ast-1.5.5-cp311-cp311-win_amd64.whl", hash = "sha256:83509f9324011c9a39faaef0922c6f720f9623afe3fe220b6d0b15638247206b"}, - {file = "typed_ast-1.5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:44f214394fc1af23ca6d4e9e744804d890045d1643dd7e8229951e0ef39429b5"}, - {file = "typed_ast-1.5.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:118c1ce46ce58fda78503eae14b7664163aa735b620b64b5b725453696f2a35c"}, - {file = "typed_ast-1.5.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be4919b808efa61101456e87f2d4c75b228f4e52618621c77f1ddcaae15904fa"}, - {file = "typed_ast-1.5.5-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:fc2b8c4e1bc5cd96c1a823a885e6b158f8451cf6f5530e1829390b4d27d0807f"}, - {file = "typed_ast-1.5.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:16f7313e0a08c7de57f2998c85e2a69a642e97cb32f87eb65fbfe88381a5e44d"}, - {file = "typed_ast-1.5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:2b946ef8c04f77230489f75b4b5a4a6f24c078be4aed241cfabe9cbf4156e7e5"}, - {file = "typed_ast-1.5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2188bc33d85951ea4ddad55d2b35598b2709d122c11c75cffd529fbc9965508e"}, - {file = "typed_ast-1.5.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0635900d16ae133cab3b26c607586131269f88266954eb04ec31535c9a12ef1e"}, - {file = "typed_ast-1.5.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57bfc3cf35a0f2fdf0a88a3044aafaec1d2f24d8ae8cd87c4f58d615fb5b6311"}, - {file = "typed_ast-1.5.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:fe58ef6a764de7b4b36edfc8592641f56e69b7163bba9f9c8089838ee596bfb2"}, - {file = "typed_ast-1.5.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d09d930c2d1d621f717bb217bf1fe2584616febb5138d9b3e8cdd26506c3f6d4"}, - {file = "typed_ast-1.5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:d40c10326893ecab8a80a53039164a224984339b2c32a6baf55ecbd5b1df6431"}, - {file = "typed_ast-1.5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fd946abf3c31fb50eee07451a6aedbfff912fcd13cf357363f5b4e834cc5e71a"}, - {file = "typed_ast-1.5.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ed4a1a42df8a3dfb6b40c3d2de109e935949f2f66b19703eafade03173f8f437"}, - {file = "typed_ast-1.5.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:045f9930a1550d9352464e5149710d56a2aed23a2ffe78946478f7b5416f1ede"}, - {file = "typed_ast-1.5.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:381eed9c95484ceef5ced626355fdc0765ab51d8553fec08661dce654a935db4"}, - {file = "typed_ast-1.5.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:bfd39a41c0ef6f31684daff53befddae608f9daf6957140228a08e51f312d7e6"}, - {file = "typed_ast-1.5.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8c524eb3024edcc04e288db9541fe1f438f82d281e591c548903d5b77ad1ddd4"}, - {file = "typed_ast-1.5.5-cp38-cp38-win_amd64.whl", hash = "sha256:7f58fabdde8dcbe764cef5e1a7fcb440f2463c1bbbec1cf2a86ca7bc1f95184b"}, - {file = "typed_ast-1.5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:042eb665ff6bf020dd2243307d11ed626306b82812aba21836096d229fdc6a10"}, - {file = "typed_ast-1.5.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:622e4a006472b05cf6ef7f9f2636edc51bda670b7bbffa18d26b255269d3d814"}, - {file = "typed_ast-1.5.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1efebbbf4604ad1283e963e8915daa240cb4bf5067053cf2f0baadc4d4fb51b8"}, - {file = "typed_ast-1.5.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0aefdd66f1784c58f65b502b6cf8b121544680456d1cebbd300c2c813899274"}, - {file = "typed_ast-1.5.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:48074261a842acf825af1968cd912f6f21357316080ebaca5f19abbb11690c8a"}, - {file = "typed_ast-1.5.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:429ae404f69dc94b9361bb62291885894b7c6fb4640d561179548c849f8492ba"}, - {file = "typed_ast-1.5.5-cp39-cp39-win_amd64.whl", hash = "sha256:335f22ccb244da2b5c296e6f96b06ee9bed46526db0de38d2f0e5a6597b81155"}, - {file = "typed_ast-1.5.5.tar.gz", hash = "sha256:94282f7a354f36ef5dbce0ef3467ebf6a258e370ab33d5b40c249fa996e590dd"}, -] - [[package]] name = "typing-extensions" version = "4.7.1" @@ -921,4 +795,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = "^3.7" -content-hash = "b2e9c397d8126250461617d77d4d4d2057274cb6b7efd6e9354d75be753f63fd" +content-hash = "6f9bfa96532cd91c19c177347ed7624d5b85c6a2fad632b2e3c6985752013cd3" diff --git a/pyproject.toml b/pyproject.toml index 10736e1..337eb10 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "hapless" -version = "0.3.0" +version = "0.4.0" description = "Run and track processes in background" authors = ["Misha Behersky "] license = "MIT" @@ -36,7 +36,6 @@ importlib-metadata = { version = "^4.11.3", python = "<3.8" } "backports.cached-property" = { version = "^1.0.2", python = "<3.8" } [tool.poetry.group.dev.dependencies] -black = "^22.3.0" pytest = "^7.1.1" isort = "^5.10.1" pytest-cov = "^3.0.0" diff --git a/tests/test_cli.py b/tests/test_cli.py index 2c8dd12..83d3bc0 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -128,9 +128,16 @@ def test_run_empty_invocation(runner): def test_clean_invocation(runner): with patch.object(runner.hapless, "clean") as clean_mock: - result = runner.invoke(cli.cli, ["clean", "--skip-failed"]) + result = runner.invoke(cli.cli, ["clean", "--all"]) assert result.exit_code == 0 - clean_mock.assert_called_once_with(True) + clean_mock.assert_called_once_with(clean_all=True) + + +def test_cleanall_invocation(runner): + with patch.object(runner.hapless, "clean") as clean_mock: + result = runner.invoke(cli.cli, ["cleanall"]) + assert result.exit_code == 0 + clean_mock.assert_called_once_with(clean_all=True) @patch("hapless.cli.get_or_exit") diff --git a/tests/test_hap.py b/tests/test_hap.py index ce2047f..81ffb3d 100644 --- a/tests/test_hap.py +++ b/tests/test_hap.py @@ -17,7 +17,7 @@ def test_random_name_generation(): assert not all_equal(names) -def test_unattached_hap(hap: Hap): +def test_unbound_hap(hap: Hap): assert hap.pid is None assert hap.proc is None assert hap.rc is None