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:
Highest Priority: Parameter-annotated command function signature
Annotated[..., Parameter()].Group.default_parameterthat the parameter belongs to.App.default_parameterof the app that registered the command.Group.default_parameterof the app that the function belongs to.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), orHave 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): ...