From e5b25b3e444557f1d3a6d94778a6211e38e58b5b Mon Sep 17 00:00:00 2001 From: Justin Ross Date: Mon, 22 Jan 2024 07:47:29 -0500 Subject: [PATCH] Skewer update --- .github/workflows/main.yaml | 2 +- external/skewer-main/.plano.py | 19 ++++------------ .../config/.github/workflows/main.yaml | 2 +- .../skewer-main/external/plano-main/README.md | 18 ++++++++++++--- .../plano/_testproject/src/chucker/tests.py | 6 +++++ .../external/plano-main/src/plano/_tests.py | 20 +++++++++++++++-- .../external/plano-main/src/plano/command.py | 22 ++++++++++--------- .../external/plano-main/src/plano/main.py | 8 +++---- .../external/plano-main/src/plano/test.py | 16 +++++++++++--- .../python/skewer/planocommands.py | 2 +- 10 files changed, 75 insertions(+), 40 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index cd492b1..db00f3c 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -24,7 +24,7 @@ on: schedule: - cron: "0 0 * * 0" jobs: - main: + test: strategy: fail-fast: false matrix: diff --git a/external/skewer-main/.plano.py b/external/skewer-main/.plano.py index 63feba6..efc44d0 100644 --- a/external/skewer-main/.plano.py +++ b/external/skewer-main/.plano.py @@ -23,24 +23,11 @@ from skewer import * @command(passthrough=True) -def test(verbose=False, quiet=False, passthrough_args=[]): - args = ["-m", "skewer.tests"] - - if verbose: - args.append("--verbose") - - if quiet: - args.append("--quiet") - - args += passthrough_args - - PlanoTestCommand().main(args=args) +def test(passthrough_args=[]): + PlanoTestCommand(skewer.tests).main(args=passthrough_args) @command def coverage(verbose=False, quiet=False): - """ - Run the tests and measure code coverage - """ check_program("coverage") with working_env(PYTHONPATH="python"): @@ -76,6 +63,8 @@ def update_plano(): """ Update the embedded Plano repo """ + check_program("curl") + make_dir("external") remove("external/plano-main") run("curl -sfL https://github.com/ssorj/plano/archive/main.tar.gz | tar -C external -xz", shell=True) diff --git a/external/skewer-main/config/.github/workflows/main.yaml b/external/skewer-main/config/.github/workflows/main.yaml index cd492b1..db00f3c 100644 --- a/external/skewer-main/config/.github/workflows/main.yaml +++ b/external/skewer-main/config/.github/workflows/main.yaml @@ -24,7 +24,7 @@ on: schedule: - cron: "0 0 * * 0" jobs: - main: + test: strategy: fail-fast: false matrix: diff --git a/external/skewer-main/external/plano-main/README.md b/external/skewer-main/external/plano-main/README.md index 2bf8c99..fb4b1c2 100644 --- a/external/skewer-main/external/plano-main/README.md +++ b/external/skewer-main/external/plano-main/README.md @@ -12,7 +12,7 @@ To install plano globally for the current user: make install ~~~ -## Example 1 +## A self-contained command with subcommands `~/.local/bin/widget`: ~~~ python @@ -37,7 +37,7 @@ Hello OK (0s) ~~~ -## Example 2 +## A self-contained test command `~/.local/bin/widget-test`: ~~~ python @@ -46,7 +46,7 @@ from plano import * @test def check(): - run("widget --message Yo") + run("widget greeting --message Yo") if __name__ == "__main__": PlanoTestCommand(sys.modules[__name__]).main() @@ -71,6 +71,18 @@ Failed: 0 All tests passed ~~~ +## Programmatic test definition + +~~~ python +from plano import * + +def test_widget(message): + run(f"widget greeting --message {message}") + +for message in "hi", "lo", "in between": + add_test(f"message-{message}", test_widget, message) +~~~ + ## Things to know * The plano command accepts command sequences in the form "this,that" diff --git a/external/skewer-main/external/plano-main/src/plano/_testproject/src/chucker/tests.py b/external/skewer-main/external/plano-main/src/plano/_testproject/src/chucker/tests.py index a556cc8..144a157 100644 --- a/external/skewer-main/external/plano-main/src/plano/_testproject/src/chucker/tests.py +++ b/external/skewer-main/external/plano-main/src/plano/_testproject/src/chucker/tests.py @@ -57,3 +57,9 @@ def process_error(): @test(disabled=True) def system_exit_(): exit(1) + +def test_widget(message): + print(message) + +for message in "hi", "lo", "in between": + add_test(f"message-{message}", test_widget, message) diff --git a/external/skewer-main/external/plano-main/src/plano/_tests.py b/external/skewer-main/external/plano-main/src/plano/_tests.py index c16ff98..c4dc0a8 100644 --- a/external/skewer-main/external/plano-main/src/plano/_tests.py +++ b/external/skewer-main/external/plano-main/src/plano/_tests.py @@ -231,6 +231,8 @@ def env_operations(): with open(out, "w") as f: print_env(file=f) + print_stack() + @test def file_operations(): with working_dir(): @@ -313,6 +315,11 @@ def file_operations(): def http_operations(): class Handler(_http.BaseHTTPRequestHandler): def do_GET(self): + if not self.path.startswith("/api"): + self.send_response(404) + self.end_headers() + return + self.send_response(200) self.end_headers() self.wfile.write(b"[1]") @@ -341,7 +348,8 @@ def run(self): self.server.serve_forever() host, port = "localhost", get_random_port() - url = "http://{}:{}".format(host, port) + url = "http://{}:{}/api".format(host, port) + missing_url = "http://{}:{}/nono".format(host, port) try: server = _http.HTTPServer((host, port), Handler) @@ -358,6 +366,9 @@ def run(self): result = http_get(url) assert result == "[1]", result + with expect_error(): + http_get(missing_url) + result = http_get(url, insecure=True) assert result == "[1]", result @@ -526,6 +537,9 @@ def logging_operations(): with expect_error(): fail("Error!") + with expect_error(): + fail("Error! {}", "Let me elaborate") + for level in ("debug", "notice", "warning", "error"): with expect_output(contains="Hello") as out: with logging_disabled(): @@ -970,6 +984,7 @@ def run_command(*args): PlanoTestCommand(chucker.tests).main(args) run_command("--verbose") + run_command("--quiet") run_command("--list") with expect_system_exit(): @@ -1185,7 +1200,6 @@ def run_command(*args): with test_project(): run_command() run_command("--help") - run_command("--quiet") with expect_system_exit(): run_command("no-such-command") @@ -1197,6 +1211,8 @@ def run_command(*args): run_command("--help", "no-such-command") run_command("extended-command", "a", "b", "--omega", "z") + run_command("extended-command", "a", "b", "--omega", "z", "--verbose") + run_command("extended-command", "a", "b", "--omega", "z", "--quiet") with expect_system_exit(): run_command("echo") diff --git a/external/skewer-main/external/plano-main/src/plano/command.py b/external/skewer-main/external/plano-main/src/plano/command.py index eb2f54f..83ab041 100644 --- a/external/skewer-main/external/plano-main/src/plano/command.py +++ b/external/skewer-main/external/plano-main/src/plano/command.py @@ -33,7 +33,7 @@ def parse_args(self, args): # pragma: nocover def configure_logging(self, args): return "warning", None - def init(self, args): + def init(self, args): # pragma: nocover raise NotImplementedError() def run(self): # pragma: nocover @@ -56,7 +56,7 @@ def main(self, args=None): except KeyboardInterrupt: pass except PlanoError as e: - if PLANO_DEBUG: + if PLANO_DEBUG: # pragma: nocover error(e) else: error(str(e)) @@ -80,6 +80,8 @@ def __init__(self, module=None, description="Run commands defined as Python func self.bound_commands = dict() self.running_commands = list() self.passthrough_args = None + self.verbose = False + self.quiet = False assert self.module is None or _inspect.ismodule(self.module), self.module @@ -135,7 +137,7 @@ def parse_args(self, args): return args def configure_logging(self, args): - if args.command is not None: + if args.command is not None and not self.bound_commands[args.command].passthrough: if args.verbose: return "debug", None @@ -152,9 +154,6 @@ def init(self, args): self.command_kwargs = dict() if args.command is not None: - self.verbose = args.verbose - self.quiet = args.quiet - for command in self.preceding_commands: command() @@ -253,10 +252,12 @@ def _process_commands(self): subparser = subparsers.add_parser(command.name, help=help, add_help=add_help, description=description, formatter_class=_argparse.RawDescriptionHelpFormatter) - subparser.add_argument("--verbose", action="store_true", - help="Print detailed logging to the console") - subparser.add_argument("--quiet", action="store_true", - help="Print no logging to the console") + + if not command.passthrough: + subparser.add_argument("--verbose", action="store_true", + help="Print detailed logging to the console") + subparser.add_argument("--quiet", action="store_true", + help="Print no logging to the console") for param in command.parameters.values(): if param.name in ("verbose", "quiet"): @@ -302,6 +303,7 @@ def _process_commands(self): "dist": "Generate distribution artifacts", "install": "Install the built artifacts on your system", "test": "Run the tests", + "coverage": "Run the tests and measure code coverage", } def command(_function=None, name=None, parameters=None, parent=None, passthrough=False, hidden=False): diff --git a/external/skewer-main/external/plano-main/src/plano/main.py b/external/skewer-main/external/plano-main/src/plano/main.py index c7db173..6b70539 100644 --- a/external/skewer-main/external/plano-main/src/plano/main.py +++ b/external/skewer-main/external/plano-main/src/plano/main.py @@ -1478,11 +1478,11 @@ def make_temp_dir(prefix="plano-", suffix="", dir=None): return _tempfile.mkdtemp(prefix=prefix, suffix=suffix, dir=dir) class temp_file: - def __init__(self, suffix="", dir=None): + def __init__(self, prefix="plano-", suffix="", dir=None): if dir is None: dir = get_system_temp_dir() - self.fd, self.file = _tempfile.mkstemp(prefix="plano-", suffix=suffix, dir=dir) + self.fd, self.file = _tempfile.mkstemp(prefix=prefix, suffix=suffix, dir=dir) def __enter__(self): return self.file @@ -1494,8 +1494,8 @@ def __exit__(self, exc_type, exc_value, traceback): remove(self.file, quiet=True) class temp_dir: - def __init__(self, suffix="", dir=None): - self.dir = make_temp_dir(suffix=suffix, dir=dir) + def __init__(self, prefix="plano-", suffix="", dir=None): + self.dir = make_temp_dir(prefix=prefix, suffix=suffix, dir=dir) def __enter__(self): return self.dir diff --git a/external/skewer-main/external/plano-main/src/plano/test.py b/external/skewer-main/external/plano-main/src/plano/test.py index 0c2c6ae..fb87d8d 100644 --- a/external/skewer-main/external/plano-main/src/plano/test.py +++ b/external/skewer-main/external/plano-main/src/plano/test.py @@ -23,8 +23,10 @@ import argparse as _argparse import asyncio as _asyncio import fnmatch as _fnmatch +import functools as _functools import importlib as _importlib import inspect as _inspect +import sys as _sys import traceback as _traceback class PlanoTestCommand(BaseCommand): @@ -103,15 +105,20 @@ def run(self): class PlanoTestSkipped(Exception): pass -def test(_function=None, name=None, timeout=None, disabled=False): +def test(_function=None, name=None, module=None, timeout=None, disabled=False): class Test: def __init__(self, function): self.function = function - self.name = nvl(name, self.function.__name__.rstrip("_").replace("_", "-")) + self.name = name + self.module = module self.timeout = timeout self.disabled = disabled - self.module = _inspect.getmodule(self.function) + if self.name is None: + self.name = self.function.__name__.strip("_").replace("_", "-") + + if self.module is None: + self.module = _inspect.getmodule(self.function) if not hasattr(self.module, "_plano_tests"): self.module._plano_tests = list() @@ -136,6 +143,9 @@ def __repr__(self): else: return Test(_function) +def add_test(name, func, *args, **kwargs): + test(_functools.partial(func, *args, **kwargs), name=name, module=_inspect.getmodule(func)) + def skip_test(reason=None): if _inspect.stack()[2].frame.f_locals["unskipped"]: return diff --git a/external/skewer-main/python/skewer/planocommands.py b/external/skewer-main/python/skewer/planocommands.py index cb696bf..28b3130 100644 --- a/external/skewer-main/python/skewer/planocommands.py +++ b/external/skewer-main/python/skewer/planocommands.py @@ -62,7 +62,7 @@ def generate(output="README.md"): generate_readme("skewer.yaml", output) @command -def render(verbose=False, quiet=False): +def render(quiet=False): """ Render README.html from README.md """