Skip to main content

cli

Version: 2.1.5

wexample-cli supplies the decorator layer — @command, @option, and @middleware — that turns plain Python methods into typed, discoverable commands for kernels built on wexample-app. Options are declared with Python types, short names, defaults, required flags, and per-value validators; a composable middleware pipeline can fan a single invocation across multiple execution contexts, run them in parallel, and abort on the first failure. It is aimed at Python developers building or extending a wexample-app kernel with new CLI commands.

Table of Contents

Installation

pip install wexample-cli

Requires Python >=3.10.

Quickstart

Install the package:

pip install wexample-cli

Declare a command inside your kernel class. @command wraps the method into a CommandMethodWrapper; each @option stacks on top in outer-to-inner order to append a typed option to it.

from wexample_cli.decorator.command import command
from wexample_cli.decorator.option import option

@option(name="name", type=str, description="Who to greet", required=True)
@command(type="demo", description="Print a greeting")
def demo__greet(context, name: str) -> None:
    context.io.log(f"Hello, {name}!")

The decorated object is a CommandMethodWrapper. You can inspect it immediately:

demo__greet.description      # "Print a greeting"
demo__greet.options[0].name  # "name"

The kernel maps the function name demo__greet to the command path demo/greet. To exercise the full decorator and middleware pipeline in a test, use the helpers in src/wexample_cli/testing/kernel.py:

from wexample_cli.testing.kernel import boot_kernel, dispatch_command

kernel = boot_kernel(MyKernel, entrypoint_path="/path/to/__main__.py")
response = dispatch_command(kernel, "demo/greet", {"name": "world"})

dispatch_command accepts pre-parsed kwargs ({"name": "world"}) or CLI-style strings (["--name", "world"]).

Tests

This project uses pytest for testing and pytest-cov for code coverage analysis.

Installation

First, install the required testing dependencies:

.venv/bin/python -m pip install pytest pytest-cov

Basic Usage

Run all tests with coverage:

.venv/bin/python -m pytest --cov --cov-report=html

Common Commands

# Run tests with coverage for a specific module
.venv/bin/python -m pytest --cov=your_module

# Show which lines are not covered
.venv/bin/python -m pytest --cov=your_module --cov-report=term-missing

# Generate an HTML coverage report
.venv/bin/python -m pytest --cov=your_module --cov-report=html

# Combine terminal and HTML reports
.venv/bin/python -m pytest --cov=your_module --cov-report=term-missing --cov-report=html

# Run specific test file with coverage
.venv/bin/python -m pytest tests/test_file.py --cov=your_module --cov-report=term-missing

Viewing HTML Reports

After generating an HTML report, open htmlcov/index.html in your browser to view detailed line-by-line coverage information.

Coverage Threshold

To enforce a minimum coverage percentage:

.venv/bin/python -m pytest --cov=your_module --cov-fail-under=80

This will cause the test suite to fail if coverage drops below 80%.

Architecture

wexample-cli is a decorator and dispatch layer that sits between a wexample-app kernel and the Python functions that implement its commands. It has no entry-point of its own; downstream kernels import its decorators, wrap their methods, and pass the resulting objects to the kernel's registration machinery.

Parts

Decorators — src/wexample_cli/decorator/

The decorators are the only thing a command author touches directly. Applied bottom-to-top on a plain function, they produce a CommandMethodWrapper:

  • @command(type, description, tags) — creates the wrapper; must be the innermost decorator.
  • @option(name, type, ...) — calls wrapper.set_option(Option(...)) to append a typed option.
  • @middleware(name, **kwargs) — calls wrapper.register_middleware(name, kwargs) to schedule a middleware class at runtime.
  • @alias(*names) — extends wrapper.aliases.
  • @screenable(interval, height) — adds --screen and --screen-interval options and pushes a pipeline wrapper that drives a refresh loop.
  • @as_sudo() — sets wrapper.sudo = True.
  • @webhook() — sets wrapper.webhook = True.
  • @option_stop_on_failure() — adds a --stop-on-failure flag option.

CommandMethodWrapper — src/wexample_cli/common/command_method_wrapper.py

The data structure produced by decoration. It carries everything the runtime needs: function, options, middlewares_attributes (names → init-kwargs, resolved at call time), pipeline_wrappers (registered in outer-to-inner order), aliases, tags, and the boolean flags sudo and webhook. It owns no execution logic.

ExtendedCommand — src/wexample_cli/command/extended_command.py

The runtime command object registered with the kernel; extends wexample_app.common.command.Command. It owns the full execution path for one CommandRequest.

AbstractMiddleware — src/wexample_cli/middleware/abstract_middleware.py

Base class for middleware. A middleware can add options dynamically (append_options), produce multiple ExecutionContext objects from a single request (build_execution_contexts), and declare whether execution should be parallel, show a progress bar, or abort on the first failure. The values "allways" and "optional" (defined in src/wexample_cli/const/middleware.py) allow a middleware to make a behaviour mandatory or user-selectable.

ExecutionContext — src/wexample_cli/context/execution_context.py

A single unit of work inside one dispatch. Holds function_kwargs, request, kernel, middleware, and an optional function override. Its __attrs_post_init__ injects context=self into function_kwargs so every command function receives it. Also provides progress-tracking helpers (create_progress_range, finish_progress, get_or_create_progress).

Exceptions — src/wexample_cli/exception/

CommandOptionMissingException and CommandOptionValidationException both extend AbstractCommandOptionException. The first is raised when a required option is absent; the second when an AbstractValidator rejects a value.

Constants — src/wexample_cli/const/

  • types.py — ParsedArgs = dict[str, Any].
  • middleware.py — the "allways" / "optional" sentinel strings.
  • tags.py — EffectTag, AudienceTag, and ScopeTag class-level string constants for @command(tags=[...]).

Testing helpers — src/wexample_cli/testing/kernel.py

boot_kernel(KernelClass, entrypoint_path) and dispatch_command(kernel, name, arguments) exercise the full decorator and dispatch pipeline from a test, identical to a real invocation.

Helper — src/wexample_cli/helper/extra_args.py

resolve_shell_command(context, command, extra_args) — resolves a shell command string from either a --command "..." option or positional -- args, preferring the positional form.

Call path

At import time (decorators run):

@alias / @as_sudo / @webhook
@screenable          →  set_option(screen, screen_interval) + register_pipeline_wrapper(screen_wrapper)
@middleware(name)    →  register_middleware(name, kwargs)
@option(...)         →  set_option(Option(...))
@command(type, ...)  →  CommandMethodWrapper(function=fn, ...)

The resulting CommandMethodWrapper is what the kernel stores; ExtendedCommand wraps it.

At invocation (ExtendedCommand.execute_request):

  1. Instantiate each middleware from the kernel's "middlewares" registry using middlewares_attributes; attach it with set_middleware (which also extends wrapper.options with the middleware's own options).
  2. If --help or -h is in the raw arguments, render help via _render_help and return.
  3. _build_function_kwargs:
    • Each middleware calls append_options to inject any dynamic options (e.g. --parallel, --progress).
    • Raw arguments (list or dict) are parsed by _parse_arguments into ParsedArgs.
    • Each declared option is resolved from parsed args, then its default, then CommandOptionMissingException if required.
    • Each non-None value is run through its validators; failure raises CommandOptionValidationException.
    • If -- passthrough tokens are present, they land in parsed_args["__extra_args__"] and are forwarded as extra_args if the function declares that parameter, otherwise CommandUnexpectedArgumentException.
  4. Build the pipeline: _make_dispatch produces the innermost callable; each entry in pipeline_wrappers is composed around it with _wrap_dispatch.
  5. Call dispatch(function_kwargs).

Inside _execute_dispatch:

  • With middlewares: each middleware calls build_execution_contexts (base returns one context; subclasses may fan out). Contexts are executed sequentially or in parallel (asyncio + ThreadPoolExecutor). Parallel runs each context with a PromptBufferOutputHandler so output is buffered per-context. Results accumulate in a MultipleResponse; a single result is unwrapped. stop_on_failure halts the loop early on FailureResponse.
  • Without middlewares: a single ExecutionContext is built by request.resolver.build_execution_context, and the function is called directly.

In both paths, ExecutionContext.__attrs_post_init__ injects context=self so the function can access context.io, context.kernel, progress handles, and the resolved function_kwargs.

Integration in the Suite

This package is part of the Wexample Suite — a collection of high-quality, modular tools designed to work seamlessly together across multiple languages and environments.

The suite includes packages for configuration management, file handling, prompts, and more. Each package can be used independently or as part of the integrated suite.

Visit the Wexample Suite documentation for the complete package ecosystem.

Dependencies

  • attrs: >=23.1.0
  • wexample-app: >=19.3.0
  • wexample-helpers: >=20.2.0
  • wexample-prompt: >=16.0.0

Versioning & Compatibility Policy

Wexample packages follow Semantic Versioning (SemVer):

  • MAJOR: Breaking changes
  • MINOR: New features, backward compatible
  • PATCH: Bug fixes, backward compatible

We maintain backward compatibility within major versions and provide clear migration guides for breaking changes.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Free to use in both personal and commercial projects.

About us

Wexample stands as a cornerstone of the digital ecosystem — a collective of seasoned engineers, researchers, and creators driven by a relentless pursuit of technological excellence. More than a media platform, it has grown into a vibrant community where innovation meets craftsmanship, and where every line of code reflects a commitment to clarity, durability, and shared intelligence.

This packages suite embodies this spirit. Trusted by professionals and enthusiasts alike, it delivers a consistent, high-quality foundation for modern development — open, elegant, and battle-tested. Its reputation is built on years of collaboration, refinement, and rigorous attention to detail, making it a natural choice for those who demand both robustness and beauty in their tools.

Wexample cultivates a culture of mastery. Each package, each contribution carries the mark of a community that values precision, ethics, and innovation — a community proud to shape the future of digital craftsmanship.

Known Limitations & Roadmap

Current limitations and planned features are tracked in the GitHub issues.

See the project roadmap for upcoming features and improvements.

Status & Compatibility

Maturity: Production-ready

Python Support: >=3.10

OS Support: Linux, macOS, Windows

Status: Actively maintained

Migration Notes

When upgrading between major versions, refer to the migration guides in the documentation.

Breaking changes are clearly documented with upgrade paths and examples.

Metadata

Release files for wexample-cli 2.1.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for wexample-cli 2.1.5
File Size Uploaded
wexample_cli-2.1.5.tar.gz 24.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for wexample-cli 2.1.5
File Interpreter ABI Platform
wexample_cli-2.1.5-py3-none-any.whl Python 3 none any Details

Total release size: 52.6 kB

Release files / wexample_cli-2.1.5.tar.gz

Download URL wexample_cli-2.1.5.tar.gz
Size 24.7 kB
Tags Source
SHA-256 checksum
How to use checksums
bb81171a061360c728f35593810b2ce0a1edba2b4d1bd399bbbfb510b87d2021
BLAKE2b-256 checksum
How to use checksums
85fc5a6eb089f48f5a8a9750dcc305ff4efc1781db756593294f25e1b319ea42
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via pdm/2.25.9 CPython/3.12.3 Linux/6.8.0-139-generic

Release files / wexample_cli-2.1.5-py3-none-any.whl

Download URL wexample_cli-2.1.5-py3-none-any.whl
Size 27.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
cec245327b2dd0a8be55c3f185ba3acc32bf5cacda432e0ec07ee3591b1454b9
BLAKE2b-256 checksum
How to use checksums
d09ebb950b36c4c09f5bab27dd81b980028ece4903876121dbe549fbda4edcba
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via pdm/2.25.9 CPython/3.12.3 Linux/6.8.0-139-generic

Release history Release notifications | RSS feed

2.1.6

2 release files

This release

2.1.5 This release

2 release files

2.1.4

2 release files

2.1.3

2 release files

2.1.2

2 release files

2.1.1

2 release files

2.1.0

2 release files

2.0.2

2 release files

2.0.1

2 release files

2.0.0

2 release files

1.3.3

2 release files

1.3.2

2 release files

1.3.1

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.7.0

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

0.0.3

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page