Default Parameter

The default values of Parameter for an app can be configured via App.default_parameter.

For example, to disable the negative flag feature across your entire app:

from cyclopts import App, Parameter

app = App(default_parameter=Parameter(negative=()))

@app.command
def foo(*, flag: bool):
    pass

app()

Consequently, --no-flag is no longer an allowed flag:

$ my-script foo --help
Usage: my-script foo [ARGS] [OPTIONS]

╭─ Parameters ──────────────────────────────────────────────────╮
│ *  --flag  [required]                                         │
╰───────────────────────────────────────────────────────────────╯

Explicitly annotating the parameter with negative overrides this configuration and works as expected:

from cyclopts import App, Parameter
from typing import Annotated

app = App(default_parameter=Parameter(negative=()))

@app.command
def foo(*, flag: Annotated[bool, Parameter(negative="--anti-flag")]):
    pass

app()
$ my-script foo --help
Usage: my-script foo [ARGS] [OPTIONS]

╭─ Parameters ──────────────────────────────────────────────────╮
│ *  --flag --anti-flag  [required]                             │
╰───────────────────────────────────────────────────────────────╯

Resolution Order

When resolving what the Parameter values for an individual function parameter should be, explicitly set attributes of higher priority Parameter s override lower priority Parameter s. The resolution order is as follows:

  1. Highest Priority: Parameter-annotated command function signature Annotated[..., Parameter()].

  2. Group.default_parameter that the parameter belongs to.

  3. App.default_parameter of the app that registered the command.

  4. Group.default_parameter of the app that the function belongs to.

  5. Lowest Priority: (2-4) recursively of the parenting app call-chain.

Any of Parameter's fields can be set to None to revert back to the true-original Cyclopts default.

Skipping Private Parameters

The Parameter.parse attribute can accept a regex pattern to selectively skip parameters based on their name. This is useful for defining "private" parameters that are externally injected (e.g. a Meta App, dependency-injection framework, etc) rather than parsed from the CLI.

For example, to skip all underscore-prefixed parameters:

from typing import Annotated
from cyclopts import App, Parameter

# The regex "^(?!_)" matches names that do NOT start with underscore.
app = App(default_parameter=Parameter(parse="^(?!_)"))

@app.command
def greet(name: str, *, _db: Database):
    user = _db.get_user(name)
    print(f"Hello {user.full_name}!")

@app.meta.default
def launcher(*tokens: Annotated[str, Parameter(show=False, allow_leading_hyphen=True)]):
    # Create shared resources
    db = Database("myapp.db")

    # Parse CLI and get ignored (non-parsed) parameters
    command, bound, ignored = app.parse_args(tokens)

    # Inject ignored parameters
    for name, type_ in ignored.items():
        if type_ is Database:
            bound.kwargs[name] = db

    return command(*bound.args, **bound.kwargs)

if __name__ == "__main__":
    app.meta()
$ my-script --help
Usage: my-script COMMAND

╭─ Commands ────────────────────────────────────────────────────╮
│ greet                                                         │
│ --help,-h  Display this message and exit.                     │
│ --version  Display application version.                       │
╰───────────────────────────────────────────────────────────────╯

$ my-script greet --help
Usage: my-script greet [ARGS] [OPTIONS]

╭─ Parameters ──────────────────────────────────────────────────╮
│ *  NAME,--name  [required]                                    │
╰───────────────────────────────────────────────────────────────╯

Notice that _db does not appear in the help screen. Parameters that don't match the regex pattern are added to the ignored dictionary returned by App.parse_args(), making them available for meta-app injection.

Like all other Parameter configurations, explicitly annotating with parse=True overrides the app-level regex:

from typing import Annotated
from cyclopts import App, Parameter

app = App(default_parameter=Parameter(parse="^(?!_)"))

@app.default
def main(name: str, *, _verbose: Annotated[bool, Parameter(parse=True)] = False):
    """_verbose IS parsed despite the underscore prefix"""

Important

Parameters that are not parsed (either via parse=False or a non-matching regex pattern) must be either:

  • Keyword-only (defined after * in the function signature), or

  • Have a default value

# Valid: keyword-only parameter
def main(*, _context: dict): ...

# Valid: has default value
def main(_context: dict = None): ...

# Invalid: positional without default - raises ValueError
def main(_context: dict): ...