Skip to content

Application components

Components are mixins (or ready-made parser classes) you attach to your app. They add arguments and participate in the parser lifecycle.

Use them when you need the feature — Clak’s core stays small without them.

Component What you get Guide
Views Tables / JSON / CSV / YAML from cli_run return values Views
Logging -v tiers, formatters, self.logger Logging
Config XDG paths + load --conf-file Config
Completion Emit shell completion scripts Completion

API pages: logging, views, config, completion.

Views

Render command results as tables (or pretty-prints) with a single mixin.

script_views.py
#!/usr/bin/env python3
"""Demo: list users with ListViewMixin and CLI column control."""

from clak import Argument, ListViewMixin, Parser


class AppMain(ListViewMixin, Parser):
    """List demo users as a table.

    Try:
      ./script_views.py
      ./script_views.py --columns name,role
      ./script_views.py --add-index
      ./script_views.py --columns name --no-expand-keys
      ./script_views.py --format json --columns name,role
      ./script_views.py --sort-columns name --sort-mode desc
    """

    class Meta:
        # True = all flags, False = none, or a subset like ("columns",)
        view_cli_options = True

    role = Argument("--role", help="Filter by role")

    def cli_run(self, role=None, **_):
        users = [
            {"name": "ada", "role": "admin", "city": "London"},
            {"name": "linus", "role": "dev", "city": "Helsinki"},
            {"name": "grace", "role": "dev", "city": "New York"},
        ]
        if role:
            users = [user for user in users if user["role"] == role]
        return users


if __name__ == "__main__":
    AppMain()

Logging

Configure -v tiers, formatters, and self.logger.

script_logging.py
#!/usr/bin/env python3
"""Demo: structured CLI logging with LoggingOptMixin.

Try:
  ./script_logging.py
  ./script_logging.py -v
  ./script_logging.py -vv
  ./script_logging.py -vvv
  ./script_logging.py -vv --log-format extended
  ./script_logging.py greet Ada
"""

from __future__ import annotations

import logging

from clak import Argument, Command, LoggingOptMixin, Parser

logger = logging.getLogger(__name__)


class GreetCmd(Parser):
    """Greet someone and emit logs at several levels."""

    name = Argument("NAME", help="Name to greet", default="World", nargs="?")

    def cli_run(self, name="World", **_):
        self.logger.debug("Preparing greeting for %s", name)
        self.logger.info("Hello, %s", name)
        self.logger.success("Greeting delivered")
        self.logger.notice("Tip: pass -v / -vv for more detail")
        print(f"Hello, {name}!")


class AppMain(LoggingOptMixin, Parser):
    """Logging demo.

    ``Meta.log_levels`` lists cumulative ``-v`` tiers as ``LEVEL|logger``.
    An empty logger name configures the root logger.
    """

    class Meta:
        log_prefix = __name__
        log_default_level = "WARNING"
        log_levels = [
            ["WARNING|" + __name__],  # default
            ["INFO|" + __name__],  # -v
            ["DEBUG|" + __name__],  # -vv
            ["DEBUG|"],  # -vvv (root — includes clak internals)
        ]
        # Kept at WARNING until maximum verbosity (-vvv here)
        log_silent = ["urllib3", "asyncio"]

    greet = Command(GreetCmd)

    def cli_run(self, **_):
        logger.warning("App module logger (logging.getLogger(__name__))")
        self.logger.info("Parser logger (self.logger) — visible from -v")
        self.logger.debug("Debug line — visible from -vv")
        print("Run a subcommand, e.g. greet — or pass -h")


if __name__ == "__main__":
    AppMain()

Config

Expose XDG paths and load a JSON/YAML config file into ctx.config:

from clak import Parser, XDGConfigMixin

class App(XDGConfigMixin, Parser):
    class Meta:
        app_name = "myapp"

    def cli_run(self, ctx, **_):
        print(ctx.config)

Details: Config.

Completion

Add a completion subcommand that prints an argcomplete shell script:

from clak import CompCmdRender, Command, Parser

class App(Parser):
    completion = Command(CompCmdRender, help="Print shell completion script")
eval "$(python myapp.py completion --executable myapp --shell bash)"

Details: Completion.

Next steps