API

class cyclopts.App(name: None | ~typing.Any | ~collections.abc.Iterable[~typing.Any] = None, help: str | None = None, usage: str | None = None, *, default_command=None, default_parameter: ~cyclopts.parameter.Parameter | None = None, config: None | ~typing.Any | ~collections.abc.Iterable[~typing.Any] = None, version: None | str | ~typing.Callable[[...], str] = <function _default_version>, version_flags: None | ~typing.Any | ~collections.abc.Iterable[~typing.Any] = ['--version'], show: bool = True, console: Console | None = None, help_flags: None | ~typing.Any | ~collections.abc.Iterable[~typing.Any] = ['--help', '-h'], help_format: ~typing.Literal['markdown', 'md', 'plaintext', 'restructuredtext', 'rst', 'rich'] | None = None, help_on_error: bool | None = None, version_format: ~typing.Literal['markdown', 'md', 'plaintext', 'restructuredtext', 'rst', 'rich'] | None = None, group: None | ~typing.Any | ~collections.abc.Iterable[~typing.Any] = None, group_arguments: None | str | ~cyclopts.group.Group = None, group_parameters: None | str | ~cyclopts.group.Group = None, group_commands: None | str | ~cyclopts.group.Group = None, validator: None | ~typing.Any | ~collections.abc.Iterable[~typing.Any] = None, name_transform: ~typing.Callable[[str], str] | None = None, sort_key=None, end_of_options_delimiter: str | None = None)

Cyclopts Application.

name: str | Iterable[str] | None = None

Name of application, or subcommand if registering to another application. Name resolution order:

  1. User specified name parameter.

  2. If a default function has been registered, the name of that function.

  3. If the module name is __main__.py, the name of the encompassing package.

  4. The value of sys.argv[0]; i.e. the name of the python script.

Multiple names can be provided in the case of a subcommand, but this is relatively unusual.

Example:

from cyclopts import App

app = App()
app.command(App(name="foo"))

@app["foo"].command
def bar():
    print("Running bar.")

app()
$ my-script foo bar
Running bar.
help: str | None = None

Text to display on help screen. If not supplied, fallbacks to parsing the docstring of function registered with App.default().

from cyclopts import App

app = App(help="This is my help string.")
app()
$ my-script --help
Usage: scratch.py COMMAND

This is my help string.

╭─ Commands ────────────────────────────────────────────────────────────╮
│ --help -h  Display this message and exit.                             │
│ --version  Display application version.                               │
╰───────────────────────────────────────────────────────────────────────╯
help_flags: str | Iterable[str] = ("--help", "-h")

CLI flags that trigger help_print(). Set to an empty list to disable this feature. Defaults to ["--help", "-h"].

help_format: Literal['plaintext', 'markdown', 'md', 'restructuredtext', 'rst'] | None = None

The markup language used in function docstring. If None, fallback to parenting help_format. If no help_format is defined, falls back to "restructuredtext".

help_on_error: bool | None = None

Prints the help-page before printing an error. If not set, attempts to inherit from parenting App, eventually defaulting to False.

version_format: Literal['plaintext', 'markdown', 'md', 'restructuredtext', 'rst'] | None = None

The markup language used in the version string. If None, fallback to parenting version_format. If no version_format is defined, falls back to resolved help_format.

usage: str | None = None

Text to be displayed in lieue of the default Usage: app COMMAND ... at the beginning of the help-page. Set to an empty-string "" to disable showing the default usage.

show: bool = True

Show this command on the help screen. Hidden commands (show=False) are still executable.

from cyclopts import App
app = App()

@app.command
def foo():
   print("Running foo.")

@app.command(show=False)
def bar():
   print("Running bar.")

app()
$ my-script foo
Running foo.

$ my-script bar
Running bar.

$ my-script --help
Usage: scratch.py COMMAND

╭─ Commands ─────────────────────────────────────────────────╮
│ foo                                                        │
│ --help -h  Display this message and exit.                  │
│ --version  Display application version.                    │
╰────────────────────────────────────────────────────────────╯
sort_key: Any = None

Modifies command display order on the help-page.

  1. If sort_key, or any of it's contents, are Callable, then invoke it sort_key(app) and apply the returned value to (2) if None, (3) otherwise.

  2. For all commands with sort_key==None (default value), sort them alphabetically. These sorted commands will be displayed after sort_key != None list (see 3).

  3. For all commands with sort_key!=None, sort them by (sort_key, app.name). It is the user's responsibility that sort_key s are comparable.

Example usage:

from cyclopts import App

app = App()

@app.command  # sort_key not specified; will be sorted AFTER bob/charlie.
def alice():
    """Alice help description."""

@app.command(sort_key=2)
def bob():
    """Bob help description."""

@app.command(sort_key=1)
def charlie():
    """Charlie help description."""

app()

Resulting help-page:

Usage: demo.py COMMAND

╭─ Commands ──────────────────────────────────────────────────╮
│ charlie    Charlie help description.                        │
│ bob        Bob help description.                            │
│ alice      Alice help description.                          │
│ --help -h  Display this message and exit.                   │
│ --version  Display application version.                     │
╰─────────────────────────────────────────────────────────────╯
version: None | str | Callable = None

Version to be displayed when a version_flags is parsed. Defaults to the version of the package instantiating App. If a Callable, it will be invoked with no arguments when version is queried.

version_flags: str | Iterable[str] = ("--version",)

Token(s) that trigger version_print(). Set to an empty list to disable version feature. Defaults to ["--version"].

console: rich.console.Console = None

Default rich.console.Console to use when displaying runtime messages. Cyclopts console resolution is as follows:

  1. Any explicitly passed in console to methods like App.__call__(), App.parse_args(), etc.

  2. The relevant subcommand's App.console attribute, if not None.

  3. The parenting App.console (and so on), if not None.

  4. If all values are None, then the default Console is used.

default_parameter: Parameter = None

Default Parameter configuration. Unspecified values of command-annotated Parameter will inherit these values. See Default Parameter for more details.

group: None | str | Group | Iterable[str | Group] = None

The group(s) that default_command belongs to.

  • If None, defaults to the "Commands" group.

  • If str, use an existing Group (from neighboring sub-commands) with name, or create a Group with provided name if it does not exist.

  • If Group, directly use it.

group_commands: Group = Group("Commands")

The default Group that sub-commands are assigned to.

group_arguments: Group = Group("Arguments")

The default Group that positional-only parameters are assigned to.

group_parameters: Group = Group("Parameters")

The default Group that non-positional-only parameters are assigned to.

validator: None | Callable | list[Callable] = []

A function (or list of functions) where all the converted CLI-provided variables will be keyword-unpacked, regardless of their positional/keyword-type in the command function signature. The python variable names will be used, which may differ from their CLI names.

Example usage:

def validator(**kwargs):
    "Raise an exception if something is invalid."

This validator runs after Parameter and Group validators.

name_transform: Callable[[str], str] | None = None

A function that converts function names to their CLI command counterparts.

The function must have signature:

def name_transform(s: str) -> str:
    ...

The returned string should be without a leading --. If None (default value), uses default_name_transform(). Subapps inherit from the first non-None parent name_transform.

config: None | Callable | Iterable[Callable] = None

A function or list of functions that are consecutively executed after parsing CLI tokens and environment variables. These function(s) are called before any conversion and validation. Each config function must have signature:

def config(apps: list["App"], commands: Tuple[str, ...], arguments: ArgumentCollection):
    """Modifies given mapping inplace with some injected values.

    Parameters
    ----------
    apps: Tuple[App, ...]
       The application hierarchy that led to the current command function.
       The current command app is the last element of this tuple.
    commands: Tuple[str, ...]
       The CLI strings that led to the current command function.
    arguments: ArgumentCollection
       Complete ArgumentCollection for the app.
       Modify this collection inplace to influence values provided to the function.
    """

The intended use-case of this feature is to allow users to specify functions that can load defaults from some external configuration. See cyclopts.config for useful builtins and Config Files for examples.

end_of_options_delimiter: str | None = None

All tokens after this delimiter will be force-interpreted as positional arguments. If no end_of_options_delimiter is set, it will default to POSIX-standard "--". Set to an empty string to disable.

version_print(console: Console | None = None) None

Print the application version.

Parameters:

console (rich.console.Console) -- Console to print version string to. If not provided, follows the resolution order defined in App.console.

__getitem__(key: str) App

Get the subapp from a command string.

All commands get registered to Cyclopts as subapps. The actual function handler is at app[key].default_command.

Example usage:

from cyclopts import App

app = App()
app.command(App(name="foo"))


@app["foo"].command
def bar():
    print("Running bar.")


app()
__iter__() Iterator[str]

Iterate over command & meta command names.

Example usage:

from cyclopts import App

app = App()


@app.command
def foo():
    pass


@app.command
def bar():
    pass


# help and version flags are treated as commands.
assert list(app) == ["--help", "-h", "--version", "foo", "bar"]
parse_commands(tokens: None | str | Iterable[str] = None, *, include_parent_meta=True) tuple[tuple[str, ...], tuple[App, ...], list[str]]

Extract out the command tokens from a command.

You are probably actually looking for parse_args().

Parameters:

tokens (Union[None, str, Iterable[str]]) -- Either a string, or a list of strings to launch a command. Defaults to sys.argv[1:]

Returns:

  • List[str] -- Strings that are interpreted as a valid command chain.

  • List[App] -- The associated App object for each element in the command chain.

  • List[str] -- The remaining non-command tokens.

command(obj: T, name: None | str | Iterable[str] = None, **kwargs: object) T
command(obj: None = None, name: None | str | Iterable[str] = None, **kwargs: object) Callable[[T], T]

Decorator to register a function as a CLI command.

Example usage:

from cyclopts import App

app = App()

@app.command
def foo():
    print("foo!")

@app.command(name="buzz")
def bar():
    print("bar!")

app()
$ my-script foo
foo!

$ my-script buzz
bar!
Parameters:
  • obj (Optional[Callable]) -- Function or App to be registered as a command.

  • name (Union[None, str, Iterable[str]]) --

    Name(s) to register the command to. If not provided, defaults to:

    • If registering an App, then the app's name.

    • If registering a function, then the function's name after applying name_transform.

  • **kwargs -- Any argument that App can take.

default(obj: T, *, validator: Callable[[...], Any] | None = None) T
default(obj: None = None, *, validator: Callable[[...], Any] | None = None) Callable[[T], T]

Decorator to register a function as the default action handler.

Example usage:

from cyclopts import App

app = App()


@app.default
def main():
    print("Hello world!")


app()
$ my-script
Hello world!
assemble_argument_collection(*, apps: Sequence[App] | None = None, default_parameter: Parameter | None = None, parse_docstring: bool = False) ArgumentCollection

Assemble the argument collection for this app.

Parameters:
  • apps (Optional[Sequence[App]]) -- List of parenting apps that lead to this app. If provided, will resolve default_parameter from the apps.

  • default_parameter (Optional[Parameter]) -- Default parameter with highest priority.

  • parse_docstring (bool) -- Parse the docstring of default_command. Set to True if we need help strings, otherwise set to False for performance reasons.

Returns:

All arguments for this app.

Return type:

ArgumentCollection

parse_known_args(tokens: None | str | Iterable[str] = None, *, console: Console | None = None, end_of_options_delimiter: str | None = None) tuple[Callable[[...], Any], BoundArguments, list[str], dict[str, Any]]

Interpret arguments into a registered function, BoundArguments, and any remaining unknown tokens.

Parameters:
  • tokens (Union[None, str, Iterable[str]]) -- Either a string, or a list of strings to launch a command. Defaults to sys.argv[1:]

  • console (rich.console.Console) -- Console to print help and runtime Cyclopts errors. If not provided, follows the resolution order defined in App.console.

  • end_of_options_delimiter (Optional[str]) -- All tokens after this delimiter will be force-interpreted as positional arguments. If None, fallback to App.end_of_options_delimiter. If that is not set, it will default to POSIX-standard "--". Set to an empty string to disable.

Returns:

  • command (Callable) -- Bare function to execute.

  • bound (inspect.BoundArguments) -- Bound arguments for command.

  • unused_tokens (List[str]) -- Any remaining CLI tokens that didn't get parsed for command.

  • ignored (dict[str, Any]) -- A mapping of python-variable-name to annotated type of any parameter with annotation parse=False. Annotated will be resolved. Intended to simplify meta apps.

parse_args(tokens: None | str | Iterable[str] = None, *, console: Console | None = None, print_error: bool = True, exit_on_error: bool = True, help_on_error: bool | None = None, verbose: bool = False, end_of_options_delimiter: str | None = None) tuple[Callable, BoundArguments, dict[str, Any]]

Interpret arguments into a function and BoundArguments.

Raises:

UnusedCliTokensError -- If any tokens remain after parsing.

Parameters:
  • tokens (Union[None, str, Iterable[str]]) -- Either a string, or a list of strings to launch a command. Defaults to sys.argv[1:].

  • console (rich.console.Console) -- Console to print help and runtime Cyclopts errors. If not provided, follows the resolution order defined in App.console.

  • print_error (bool) -- Print a rich-formatted error on error. Defaults to True.

  • exit_on_error (bool) -- If there is an error parsing the CLI tokens invoke sys.exit(1). Otherwise, continue to raise the exception. Defaults to True.

  • help_on_error (bool) -- Prints the help-page before printing an error, overriding App.help_on_error. Defaults to None (interpret from App, eventually defaulting to False).

  • verbose (bool) -- Populate exception strings with more information intended for developers. Defaults to False.

  • end_of_options_delimiter (Optional[str]) -- All tokens after this delimiter will be force-interpreted as positional arguments. If None, fallback to App.end_of_options_delimiter. If that is not set, it will default to POSIX-standard "--". Set to an empty string to disable.

Returns:

  • command (Callable) -- Function associated with command action.

  • bound (inspect.BoundArguments) -- Parsed and converted args and kwargs to be used when calling command.

  • ignored (dict[str, Any]) -- A mapping of python-variable-name to type-hint of any parameter with annotation parse=False. Annotated will be resolved. Intended to simplify meta apps.

__call__(tokens: None | str | Iterable[str] = None, *, console: Console | None = None, print_error: bool = True, exit_on_error: bool = True, help_on_error: bool | None = None, verbose: bool = False, end_of_options_delimiter: str | None = None)

Interprets and executes a command.

Parameters:
  • tokens (Union[None, str, Iterable[str]]) -- Either a string, or a list of strings to launch a command. Defaults to sys.argv[1:].

  • console (rich.console.Console) -- Console to print help and runtime Cyclopts errors. If not provided, follows the resolution order defined in App.console.

  • print_error (bool) -- Print a rich-formatted error on error. Defaults to True.

  • exit_on_error (bool) -- If there is an error parsing the CLI tokens invoke sys.exit(1). Otherwise, continue to raise the exception. Defaults to True.

  • help_on_error (bool) -- Prints the help-page before printing an error, overriding App.help_on_error. Defaults to None (interpret from App, eventually defaulting to False).

  • verbose (bool) -- Populate exception strings with more information intended for developers. Defaults to False.

  • end_of_options_delimiter (Optional[str]) -- All tokens after this delimiter will be force-interpreted as positional arguments. If None, fallback to App.end_of_options_delimiter. If that is not set, it will default to POSIX-standard "--".

Returns:

return_value -- The value the command function returns.

Return type:

Any

help_print(tokens: Annotated[None | str | Iterable[str], Parameter(show=False)] = None, *, console: Annotated[Console | None, Parameter(parse=False)] = None) None

Print the help page.

Parameters:
  • tokens (Union[None, str, Iterable[str]]) -- Tokens to interpret for traversing the application command structure. If not provided, defaults to sys.argv.

  • console (rich.console.Console) -- Console to print help and runtime Cyclopts errors. If not provided, follows the resolution order defined in App.console.

interactive_shell(prompt: str = '$ ', quit: None | str | Iterable[str] = None, dispatcher: Dispatcher | None = None, **kwargs) None

Create a blocking, interactive shell.

All registered commands can be executed in the shell.

Parameters:
  • prompt (str) -- Shell prompt. Defaults to "$ ".

  • quit (Union[str, Iterable[str]]) -- String or list of strings that will cause the shell to exit and this method to return. Defaults to ["q", "quit"].

  • dispatcher (Optional[Dispatcher]) --

    Optional function that subsequently invokes the command. The dispatcher function must have signature:

    def dispatcher(command: Callable, bound: inspect.BoundArguments) -> Any:
        return command(*bound.args, **bound.kwargs)
    

    The above is the default dispatcher implementation.

  • **kwargs -- Get passed along to parse_args().

update(app: App)

Copy over all commands from another App.

Commands from the meta app will not be copied over.

Parameters:

app (cyclopts.App) -- All commands from this application will be copied over.

class cyclopts.Parameter(name=None, converter: ~typing.Callable[[~typing.Any, ~typing.Sequence[~cyclopts.token.Token]], ~typing.Any] | None = None, validator=(), negative: None | ~typing.Any | ~collections.abc.Iterable[~typing.Any] = None, group: None | ~typing.Any | ~collections.abc.Iterable[~typing.Any] = None, parse=None, show: bool | None = None, show_default: bool | None = None, show_choices=None, help: str | None = None, show_env_var=None, env_var=None, env_var_split: ~typing.Callable = <function env_var_split>, negative_bool=None, negative_iterable=None, required: bool | None = None, allow_leading_hyphen: bool = False, accepts_keys: bool | None = None, consume_multiple=None, *, name_transform: ~typing.Callable[[str], str] | None = None, json_dict: bool | None = None, json_list: bool | None = None)

Cyclopts configuration for individual function parameters with Annotated.

Example usage:

from cyclopts import app, Parameter
from typing import Annotated

app = App()


@app.default
def main(foo: Annotated[int, Parameter(name="bar")]):
    print(foo)


app()
$ my-script 100
100

$ my-script --bar 100
100
name: None | str | Iterable[str] = None

Name(s) to expose to the CLI. If not specified, cyclopts will apply name_transform to the python parameter name.

from cyclopts import App, Parameter
from typing import Annotated

app = App()

@app.default
def main(foo: Annotated[int, Parameter(name=("bar", "-b"))]):
   print(f"{foo=}")

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

╭─ Commands ─────────────────────────────────────────────────────╮
│ --help -h  Display this message and exit.                      │
│ --version  Display application version.                        │
╰────────────────────────────────────────────────────────────────╯
╭─ Parameters ───────────────────────────────────────────────────╮
│ *  BAR --bar  -b  [required]                                   │
╰────────────────────────────────────────────────────────────────╯

$ my-script --bar 100
foo=100

$ my-script -b 100
foo=100

If specifying name in a nested data structure (e.g. a dataclass), beginning the name with a hyphen - will override any hierarchical dot-notation.

from cyclopts import App, Parameter
from dataclasses import dataclass
from typing import Annotated

app = App()

@dataclass
class User:
   id: int  # default behavior
   email: Annotated[str, Parameter(name="--email")]  # overrides
   pwd: Annotated[str, Parameter(name="password")]  # dot-notation with parent

@app.command
def create(user: User):
   print(f"Creating {user=}")

app()
$ my-script create --help
Usage: scratch.py create [ARGS] [OPTIONS]

╭─ Parameters ───────────────────────────────────────────────────╮
│ *  USER.ID --user.id  [required]                               │
│ *  EMAIL --email      [required]                               │
│ *  USER.PASSWORD      [required]                               │
│      --user.password                                           │
╰────────────────────────────────────────────────────────────────╯
converter: Callable | None = None

A function that converts tokens into an object. The converter should have signature:

def converter(type_, tokens) -> Any:
    pass

Where type_ is the parameter's type hint, and tokens is either:

  • A list[cyclopts.Token] of CLI tokens (most commonly).

    from cyclopts import App, Parameter
    from typing import Annotated
    
    app = App()
    
    def converter(type_, tokens):
       assert type_ == tuple[int, int]
       return tuple(2 * int(x.value) for x in tokens)
    
    @app.default
    def main(coordinates: Annotated[tuple[int, int], Parameter(converter=converter)]):
       print(f"{coordinates=}")
    
    app()
    
    $ python my-script.py 7 12
    coordinates=(14, 24)
    
  • A dict of Token if keys are specified in the CLI. E.g.

    $ python my-script.py --foo.key1=val1
    

    would be parsed into:

    tokens = {
       "key1": ["val1"],
    }
    

If not provided, defaults to Cyclopts's internal coercion engine. If a pydantic type-hint is provided, Cyclopts will disable it's internal coercion engine (including this converter argument) and leave the coercion to pydantic.

validator: None | Callable | Iterable[Callable] = None

A function (or list of functions) that validates data returned by the converter.

def validator(type_, value: Any) -> None:
    pass  # Raise a TypeError, ValueError, or AssertionError here if data is invalid.
group: None | str | Group | Iterable[str | Group] = None

The group(s) that this parameter belongs to. This can be used to better organize the help-page, and/or to add additional conversion/validation logic (such as ensuring mutually-exclusive arguments).

If None, defaults to one of the following groups:

  1. Parenting App.group_arguments if the parameter is POSITIONAL_ONLY. By default, this is Group("Arguments").

  2. Parenting App.group_parameters otherwise. By default, this is Group("Parameters").

See Groups for examples.

negative: None | str | Iterable[str] = None

Name(s) for empty iterables or false boolean flags.

Set to an empty list or string to disable the creation of negative flags.

Example usage:

from cyclopts import App, Parameter
from typing import Annotated

app = App()

@app.default
def main(*, verbose: Annotated[bool, Parameter(negative="--quiet")] = False):
   print(f"{verbose=}")

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

╭─ Commands ─────────────────────────────────────────────────────╮
│ --help -h  Display this message and exit.                      │
│ --version  Display application version.                        │
╰────────────────────────────────────────────────────────────────╯
╭─ Parameters ───────────────────────────────────────────────────╮
│ --verbose --quiet  [default: False]                            │
╰────────────────────────────────────────────────────────────────╯
negative_bool: str | None = None

Prefix for negative boolean flags. Defaults to "no-".

negative_iterable: str | None = None

Prefix for empty iterables (like lists and sets) flags. Defaults to "empty-".

allow_leading_hyphen: bool = False

Allow parsing non-numeric values that begin with a hyphen -. This is disabled (False) by default, allowing for more helpful error messages for unknown CLI options.

parse: bool | None = True

Attempt to use this parameter while parsing. Annotated parameter must be keyword-only. This is intended to be used with meta apps for injecting values.

required: bool | None = None

Indicates that the parameter must be supplied. Defaults to inferring from the function signature; i.e. False if the parameter has a default, True otherwise.

show: bool | None = None

Show this parameter on the help screen. Defaults to parse value (default: True).

show_default: bool | None = None

If a variable has a default, display the default on the help page. Defaults to None, similar to True, but will not display the default if it's None.

show_choices: bool | None = True

If a variable has a set of choices, display the choices on the help page.

help: str | None = None

Help string to be displayed on the help page. If not specified, defaults to the docstring.

show_env_var: bool | None = True

If a variable has env_var set, display the variable name on the help page.

env_var: None | str | Iterable[str] = None

Fallback to environment variable(s) if CLI value not provided. If multiple environment variables are given, the left-most environment variable with a set value will be used. If no environment variable is set, Cyclopts will fallback to the function-signature default.

env_var_split: Callable = cyclopts.env_var_split

Function that splits up the read-in env_var value. The function must have signature:

def env_var_split(type_: type, val: str) -> list[str]:
    ...

where type_ is the associated parameter type-hint, and val is the environment value.

name_transform: Callable[[str], str] | None = None

A function that converts python parameter names to their CLI command counterparts.

The function must have signature:

def name_transform(s: str) -> str:
    ...

If None (default value), uses cyclopts.default_name_transform().

accepts_keys: bool | None = None

If False, treat the user-defined class annotation similar to a tuple. Individual class sub-parameters will not be addressable by CLI keywords. The class will consume enough tokens to populate all required positional parameters.

Default behavior (accepts_keys=True):

from cyclopts import App, Parameter
from typing import Annotated

app = App()

class Image:
   def __init__(self, path, label):
      self.path = path
      self.label = label

   def __repr__(self):
      return f"Image(path={self.path!r}, label={self.label!r})"

@app.default
def main(image: Image):
   print(f"{image=}")

app()
$ my-program --help
Usage: main COMMAND [ARGS] [OPTIONS]

╭─ Commands ──────────────────────────────────────────────────────────╮
│ --help -h  Display this message and exit.                           │
│ --version  Display application version.                             │
╰─────────────────────────────────────────────────────────────────────╯
╭─ Parameters ────────────────────────────────────────────────────────╮
│ *  IMAGE.PATH --image.path    [required]                            │
│ *  IMAGE.LABEL --image.label  [required]                            │
╰─────────────────────────────────────────────────────────────────────╯

$ my-program foo.jpg nature
image=Image(path='foo.jpg', label='nature')

$ my-program --image.path foo.jpg --image.label nature
image=Image(path='foo.jpg', label='nature')

Behavior when accepts_keys=False:

# Modify the default command function's signature.
@app.default
def main(image: Annotated[Image, Parameter(accepts_keys=False)]):
   print(f"{image=}")
$ my-program --help
Usage: main COMMAND [ARGS] [OPTIONS]

╭─ Commands ──────────────────────────────────────────────────────────╮
│ --help -h  Display this message and exit.                           │
│ --version  Display application version.                             │
╰─────────────────────────────────────────────────────────────────────╯
╭─ Parameters ────────────────────────────────────────────────────────╮
│ *  IMAGE --image  [required]                                        │
╰─────────────────────────────────────────────────────────────────────╯

$ my-program foo.jpg nature
image=Image(path='foo.jpg', label='nature')

$ my-program --image foo.jpg nature
image=Image(path='foo.jpg', label='nature')
consume_multiple: bool | None = None

When a parameter is specified by keyword, consume multiple elements worth of CLI tokens. Will consume tokens until the stream is exhausted, or an and allow_leading_hyphen is False If False (default behavior), then only a single element worth of CLI tokens will be consumed.

from cyclopts import App
from pathlib import Path

app = App()

@app.default
def rules(files: list[Path], ext: list[str] = []):
   pass

app()
$ cmd --ext .pdf --ext .html foo.md bar.md
json_dict: bool | None = None

Allow for the parsing of json-dict-strings as data. If None (default behavior), acts like True, unless the annotated type is union'd with str. When True, data will be parsed as json if the following conditions are met:

  1. The parameter is specified as a keyword option; e.g. --movie.

  2. The referenced parameter is dataclass-like.

  3. The first character of the token is a {.

json_list: bool | None = None

Allow for the parsing of json-list-strings as data. If None (default behavior), acts like True, unless the annotated type has each element type str. When True, data will be parsed as json if the following conditions are met:

  1. The referenced parameter is iterable (not including str).

  2. The first character of the token is a [.

classmethod combine(*parameters: Parameter | None) Parameter

Returns a new Parameter with combined values of all provided parameters.

Parameters:

*parameters (Optional[Parameter]) -- Parameters who's attributes override self attributes. Ordered from least-to-highest attribute priority.

classmethod default() Parameter

Create a Parameter with all Cyclopts-default values.

This is different than just Parameter because the default values will be recorded and override all upstream parameter values.

__call__(obj: T) T

Decorator interface for annotating a function/class with a Parameter.

Most commonly used for directly configuring a class:

@Parameter(...)
class Foo: ...
class cyclopts.Group(name: str = '', help: str = '', *, show: bool | None = None, sort_key=None, validator=None, default_parameter: Parameter | None = None)

A group of parameters and/or commands in a CLI application.

name: str = ""

Group name used for the help-page and for group-referenced-by-string. This is a title, so the first character should be capitalized. If a name is not specified, it will not be shown on the help-page.

help: str = ""

Additional documentation shown on the help-page. This will be displayed inside the group's panel, above the parameters/commands.

show: bool | None = None

Show this group on the help-page. Defaults to None, which will only show the group if a name is provided.

sort_key: Any = None

Modifies group-panel display order on the help-page.

  1. If sort_key, or any of it's contents, are Callable, then invoke it sort_key(group) and apply the returned value to (2) if None, (3) otherwise.

  2. For all groups with sort_key==None (default value), sort them alphabetically. These sorted groups will be displayed after sort_key != None list (see 3).

  3. For all groups with sort_key!=None, sort them by (sort_key, group.name). It is the user's responsibility that sort_key s are comparable.

Example usage:

from cyclopts import App, Group

app = App()

@app.command(group=Group("4", sort_key=5))
def cmd1():
    pass


@app.command(group=Group("3", sort_key=lambda x: 10))
def cmd2():
    pass


@app.command(group=Group("2", sort_key=lambda x: None))
def cmd3():
    pass


@app.command(group=Group("1"))
def cmd4():
    pass

app()

Resulting help-page:

Usage: app COMMAND

╭─ 4 ────────────────────────────────────────────────────────────────╮
│ cmd1                                                               │
╰────────────────────────────────────────────────────────────────────╯
╭─ 3 ────────────────────────────────────────────────────────────────╮
│ cmd2                                                               │
╰────────────────────────────────────────────────────────────────────╯
╭─ 1 ────────────────────────────────────────────────────────────────╮
│ cmd4                                                               │
╰────────────────────────────────────────────────────────────────────╯
╭─ 2 ────────────────────────────────────────────────────────────────╮
│ cmd3                                                               │
╰────────────────────────────────────────────────────────────────────╯
╭─ Commands ─────────────────────────────────────────────────────────╮
│ --help,-h  Display this message and exit.                          │
│ --version  Display application version.                            │
╰────────────────────────────────────────────────────────────────────╯
default_parameter: Parameter | None = None

Default Parameter in the parameter-resolution-stack that goes between App.default_parameter and the function signature's Annotated Parameter. The provided Parameter is not allowed to have a group value.

validator: Callable | None = None

A function (or list of functions) that validates an ArgumentCollection.

Example usage:

def validator(argument_collection: ArgumentCollection):
    "Raise an exception if something is invalid."

Validators are not invoked for command groups.

classmethod create_ordered(name='', help='', *, show=None, sort_key=None, validator=None, default_parameter=None)

Create a group with a globally incrementing sort_key.

Used to create a group that will be displayed after a previously instantiated Group.create_ordered() group on the help-page.

Parameters:
  • name (str) -- Group name used for the help-page and for group-referenced-by-string. This is a title, so the first character should be capitalized. If a name is not specified, it will not be shown on the help-page.

  • help (str) -- Additional documentation shown on the help-page. This will be displayed inside the group's panel, above the parameters/commands.

  • show (Optional[bool]) -- Show this group on the help-page. Defaults to None, which will only show the group if a name is provided.

  • sort_key (Any) -- If provided, prepended to the globally incremented counter value (i.e. has priority during sorting).

  • validator (Union[None, Callable[["ArgumentCollection"], Any], Iterable[Callable[["ArgumentCollection"], Any]]]) -- Group validator to collectively apply.

  • default_parameter (Optional[cyclopts.Parameter]) -- Default parameter for elements within the group.

class cyclopts.Token(*, keyword: str | None = None, value: str = '', source: str = '', index: int = 0, keys: tuple[str, ...] = (), implicit_value: ~typing.Any = <UNSET>)

Tracks how a user supplied a value to the application.

keyword: str | None = None

Unadulterated user-supplied keyword like --foo or --foo.bar.baz; None when token was pared positionally. Could also be something like tool.project.foo if from non-cli sources.

value: str = ""

The parsed token value (unadulterated).

source: str = ""

Where the token came from; used for error message purposes. Cyclopts uses the string cli for cli-parsed tokens.

index: int = 0

The relative positional index in which the value was provided.

keys: tuple[str, ...] = ()

The additional parsed python variable keys from keyword.

Only used for Arguments that take arbitrary keys.

implicit_value: Any = cyclopts.UNSET

Final value that should be used instead of converting from value.

Commonly used for boolean flags.

Ignored if UNSET.

class cyclopts.field_info.FieldInfo(names: tuple[str, ...] = (), kind: _ParameterKind = _ParameterKind.POSITIONAL_OR_KEYWORD, *, required: bool = False, default: Any, annotation: Any, help: str | None = None)

Extension of inspect.Parameter.

class cyclopts.Argument(*, tokens: list[~cyclopts.token.Token] = NOTHING, field_info: ~cyclopts.field_info.FieldInfo = NOTHING, parameter: ~cyclopts.parameter.Parameter = NOTHING, hint: ~typing.Any = <class 'str'>, index: int | None = None, keys: tuple[str, ...] = (), value: ~typing.Any = <UNSET>)

Encapsulates functionality and additional contextual information for parsing a parameter.

An argument is defined as anything that would have its own entry in the help page.

tokens: list[Token]

List of Token parsed from various sources. Do not directly mutate; see append().

field_info: FieldInfo

Additional information about the parameter from surrounding python syntax.

parameter: Parameter

Fully resolved user-provided Parameter.

hint: Any

The type hint for this argument; may be different from FieldInfo.annotation.

index: int | None

Associated python positional index for argument. If None, then cannot be assigned positionally.

keys: tuple[str, ...]

Python keys that lead to this leaf.

self.parameter.name and self.keys can naively disagree! For example, a self.parameter.name="--foo.bar.baz" could be aliased to "--fizz". The resulting self.keys would be ("bar", "baz").

This is populated based on type-hints and class-structure, not Parameter.name.

from cyclopts import App, Parameter
from dataclasses import dataclass
from typing import Annotated

app = App()


@dataclass
class User:
    id: int
    name: Annotated[str, Parameter(name="--fullname")]


@app.default
def main(user: User):
    pass


for argument in app.assemble_argument_collection():
    print(f"name: {argument.name:16} hint: {str(argument.hint):16} keys: {str(argument.keys)}")
$ my-script
name: --user.id        hint: <class 'int'>    keys: ('id',)
name: --fullname       hint: <class 'str'>    keys: ('name',)
children: ArgumentCollection

Collection of other Argument that eventually culminate into the python variable represented by field_info.

property value

Converted value from last convert() call.

This value may be stale if fields have changed since last convert() call. UNSET if convert() has not yet been called with tokens.

property show_default: bool

Show the default value on the help page.

match(term: str | int, *, transform: Callable[[str], str] | None = None, delimiter: str = '.') tuple[tuple[str, ...], Any]

Match a name search-term, or a positional integer index.

Raises:

ValueError -- If no match is found.

Returns:

  • Tuple[str, ...] -- Leftover keys after matching to this argument. Used if this argument accepts_arbitrary_keywords.

  • Any -- Implicit value. None if no implicit value is applicable.

append(token: Token)

Safely add a Token.

property has_tokens: bool

This argument, or a child argument, has at least 1 parsed token.

property children_recursive: ArgumentCollection
convert(converter: Callable | None = None)

Converts tokens into value.

Parameters:

converter (Optional[Callable]) -- Converter function to use. Overrides self.parameter.converter

Returns:

The converted data. Same as value.

Return type:

Any

validate(value)

Validates provided value.

Parameters:

value -- Value to validate.

Returns:

The converted data. Same as value.

Return type:

Any

convert_and_validate(converter: Callable | None = None)

Converts and validates tokens into value.

Parameters:

converter (Optional[Callable]) -- Converter function to use. Overrides self.parameter.converter

Returns:

The converted data. Same as value.

Return type:

Any

token_count(keys: tuple[str, ...] = ())

The number of string tokens this argument consumes.

Parameters:

keys (tuple[str, ...]) -- The python keys into this argument. If provided, returns the number of string tokens that specific data type within the argument consumes.

Returns:

  • int -- Number of string tokens to create 1 element.

  • consume_all (bool) -- True if this data type is iterable.

property negatives

Negative flags from Parameter.get_negatives().

property name: str

The first provided name this argument goes by.

property names: tuple[str, ...]

Names the argument goes by (both positive and negative).

env_var_split(value: str, delimiter: str | None = None) list[str]

Split a given value with Parameter.env_var_split().

property show: bool

Show this argument on the help page.

If an argument has child arguments, don't show it on the help-page.

property required: bool

Whether or not this argument requires a user-provided value.

class cyclopts.ArgumentCollection(*args)

A list-like container for Argument.

copy() ArgumentCollection

Returns a shallow copy of the ArgumentCollection.

match(term: str | int, *, transform: Callable[[str], str] | None = None, delimiter: str = '.') tuple[Argument, tuple[str, ...], Any]

Matches CLI keyword or index to their Argument.

Parameters:

term (str | int) --

One of:

  • str keyword like "--foo" or "-f" or "--foo.bar.baz".

  • int global positional index.

Raises:

ValueError -- If the provided term doesn't match.

Returns:

  • Argument -- Matched Argument.

  • Tuple[str, ...] -- Python keys into Argument. Non-empty iff Argument accepts keys.

  • Any -- Implicit value (if a flag). None otherwise.

property groups
filter_by(*, group: Group | None = None, has_tokens: bool | None = None, has_tree_tokens: bool | None = None, keys_prefix: tuple[str, ...] | None = None, kind: _ParameterKind | None = None, parse: bool | None = None, show: bool | None = None, value_set: bool | None = None) ArgumentCollection

Filter the ArgumentCollection.

All non-None filters will be applied.

Parameters:
  • group (Optional[Group]) -- The Group the arguments should be in.

  • has_tokens (Optional[bool]) -- Immediately has tokens (not including children).

  • has_tree_tokens (Optional[bool]) -- Argument and/or it's children have parsed tokens.

  • kind (Optional[inspect._ParameterKind]) -- The kind of the argument.

  • parse (Optional[bool]) -- If the argument is intended to be parsed or not.

  • show (Optional[bool]) -- The Argument is intended to be show on the help page.

  • value_set (Optional[bool]) -- The converted value is set.

class cyclopts.UNSET

Special sentinel value indicating that no data was provided. Do not instantiate.

cyclopts.default_name_transform(s: str) str

Converts a python identifier into a CLI token.

Performs the following operations (in order):

  1. Convert the string to all lowercase.

  2. Replace _ with -.

  3. Strip any leading/trailing - (also stripping _, due to point 2).

Intended to be used with App.name_transform and Parameter.name_transform.

Parameters:

s (str) -- Input python identifier string.

Returns:

Transformed name.

Return type:

str

cyclopts.env_var_split(type_: Any, val: str, *, delimiter: str | None = None) list[str]

Type-dependent environment variable value splitting.

Converts a single string into a list of strings. Splits when:

  • The type_ is some variant of Iterable[pathlib.Path] objects. If Windows, split on ;, otherwise split on :.

  • Otherwise, if the type_ is an Iterable, split on whitespace. Leading/trailing whitespace of each output element will be stripped.

This function is the default value for cyclopts.App.env_var_split.

Parameters:
  • type (type) -- Type hint that we will eventually coerce into.

  • val (str) -- String to split.

  • delimiter (Optional[str]) -- Delimiter to split val on. If None, defaults to whitespace.

Returns:

List of individual string tokens.

Return type:

list[str]

cyclopts.edit(initial_text: str = '', *, fallback_editors: Sequence[str] = ('nano', 'vim', 'notepad', 'gedit'), editor_args: Sequence[str] = (), path: str | Path = '', encoding: str = 'utf-8', save: bool = True, required: bool = True) str

Get text input from a user by launching their default text editor.

Parameters:
  • initial_text (str) -- Initial text to populate the text file with.

  • fallback_editors (Sequence[str]) -- If the text editor cannot be determined from the environment variable EDITOR, attempt to use these text editors in the order provided.

  • editor_args (Sequence[str]) -- Additional CLI arguments that are passed along to the editor-launch command.

  • path (Union[str, Path]) -- If specified, the path to the file that should be opened. Text editors typically display this, so a custom path may result in a better user-interface. Defaults to a temporary text file.

  • encoding (str) -- File encoding to use.

  • save (bool) -- Require the user to save before exiting the editor. Otherwise raises EditorDidNotSaveError.

  • required (bool) -- Require for the saved text to be different from initial_text. Otherwise raises EditorDidNotChangeError.

Raises:
Returns:

The resulting text that was saved by the text editor.

Return type:

str

cyclopts.run(callable: Callable[[...], Coroutine[None, None, V]], /) V
cyclopts.run(callable: Callable[[...], V], /) V

Run the given callable as a CLI command and return its result.

The callable may also be a coroutine function. This function is syntax sugar for very simple use cases, and is roughly equivalent to:

from cyclopts import App

app = App()
app.default(callable)
app()

Example usage:

import cyclopts


def main(name: str, age: int):
    print(f"Hello {name}, you are {age} years old.")


cyclopts.run(main)

Validators

Cyclopts has several builtin validators for common CLI inputs.

class cyclopts.validators.LimitedChoice(min: int = 0, max: int | None = None)

Group validator that limits the number of selections per group.

Commonly used for enforcing mutually-exclusive parameters (default behavior).

Parameters:
  • min (int) -- The minimum (inclusive) number of CLI parameters allowed.

  • max (Optional[int]) -- The maximum (inclusive) number of CLI parameters allowed. Defaults to 1 if min==0, min otherwise.

class cyclopts.validators.MutuallyExclusive

Alias for LimitedChoice to make intentions more obvious.

Only 1 argument in the group can be supplied a value.

class cyclopts.validators.Number(*, lt: int | float | None = None, lte: int | float | None = None, gt: int | float | None = None, gte: int | float | None = None, modulo: int | float | None = None)

Limit input number to a value range.

Example Usage:

from cyclopts import App, Parameter, validators
from typing import Annotated

app = App()


@app.default
def main(age: Annotated[int, Parameter(validator=validators.Number(gte=0, lte=150))]):
    print(f"You are {age} years old.")


app()
$ my-script 100
You are 100 years old.

$ my-script -1
╭─ Error ───────────────────────────────────────────────────────╮
│ Invalid value "-1" for "AGE". Must be >= 0.                   │
╰───────────────────────────────────────────────────────────────╯

$ my-script 200
╭─ Error ───────────────────────────────────────────────────────╮
│ Invalid value "200" for "AGE". Must be <= 150.                │
╰───────────────────────────────────────────────────────────────╯
lt: int | float | None

Input value must be less than this value.

lte: int | float | None

Input value must be less than or equal this value.

gt: int | float | None

Input value must be greater than this value.

gte: int | float | None

Input value must be greater than or equal this value.

modulo: int | float | None

Input value must be a multiple of this value.

class cyclopts.validators.Path(*, exists: bool = False, file_okay: bool = True, dir_okay: bool = True, ext: None | Any | Iterable[Any] = None)

Assertions on properties of pathlib.Path.

Example Usage:

from cyclopts import App, Parameter, validators
from pathlib import Path
from typing import Annotated

app = App()


@app.default
def main(
    # ``src`` must be a file that exists.
    src: Annotated[Path, Parameter(validator=validators.Path(exists=True, dir_okay=False))],
    # ``dst`` must be a path that does **not** exist.
    dst: Annotated[Path, Parameter(validator=validators.Path(dir_okay=False, file_okay=False))],
):
    "Copies src->dst."
    dst.write_bytes(src.read_bytes())


app()
$ my-script foo.bin bar.bin  # if foo.bin does not exist
╭─ Error ───────────────────────────────────────────────────────╮
│ Invalid value "foo.bin" for "SRC". "foo.bin" does not exist.  │
╰───────────────────────────────────────────────────────────────╯

$ my-script foo.bin bar.bin  # if bar.bin exists
╭─ Error ───────────────────────────────────────────────────────╮
│ Invalid value "bar.bin" for "DST". "bar.bin" already exists.  │
╰───────────────────────────────────────────────────────────────╯
exists: bool

If True, specified path must exist. Defaults to False.

file_okay: bool

If path exists, check it's type:

  • If True, specified path may be an existing file.

  • If False, then existing files are not allowed.

Defaults to True.

dir_okay: bool

If path exists, check it's type:

  • If True, specified path may be an existing directory.

  • If False, then existing directories are not allowed.

Defaults to True.

ext: str | Sequence[str]

Supplied path must have this extension (case insensitive). May or may not include the ".".

Types

Cyclopts has builtin pre-defined annotated-types for common conversion and validation configurations. All definitions in this section are simply predefined annotations for convenience:

Annotated[..., Parameter(...)]

Due to Cyclopts's advanced Parameter resolution engine, these annotations can themselves be annotated to further configure behavior. E.g:

Annotated[PositiveInt, Parameter(...)]

Path

Path annotated types for checking existence, type, and performing path-resolution. All of these types will also work on sequence of paths (e.g. tuple[Path, Path] or list[Path]).

cyclopts.types.ExistingPath

A Path file or directory that must exist.

alias of Annotated[Path, Parameter(validator=(Path(exists=True, file_okay=True, dir_okay=True, ext=()),))]

cyclopts.types.ResolvedPath

A Path file or directory. resolve() is invoked prior to returning the path.

cyclopts.types.ResolvedExistingPath

A Path file or directory that must exist. resolve() is invoked prior to returning the path.

cyclopts.types.Directory

A Path that must be a directory (or not exist).

alias of Annotated[Path, Parameter(validator=(Path(exists=False, file_okay=False, dir_okay=True, ext=()),))]

cyclopts.types.ExistingDirectory

A Path directory that must exist.

alias of Annotated[Path, Parameter(validator=(Path(exists=True, file_okay=False, dir_okay=True, ext=()),))]

cyclopts.types.ResolvedDirectory

A Path directory. resolve() is invoked prior to returning the path.

cyclopts.types.ResolvedExistingDirectory

A Path directory that must exist. resolve() is invoked prior to returning the path.

cyclopts.types.File

A File that must be a file (or not exist).

alias of Annotated[Path, Parameter(validator=(Path(exists=False, file_okay=True, dir_okay=False, ext=()),))]

cyclopts.types.ExistingFile

A Path file that must exist.

alias of Annotated[Path, Parameter(validator=(Path(exists=True, file_okay=True, dir_okay=False, ext=()),))]

cyclopts.types.ResolvedFile

A Path file. resolve() is invoked prior to returning the path.

cyclopts.types.ResolvedExistingFile

A Path file that must exist. resolve() is invoked prior to returning the path.

cyclopts.types.BinPath

A Path that must have extension bin.

alias of Annotated[Path, Parameter(validator=(Path(exists=False, file_okay=True, dir_okay=False, ext=('bin',)),))]

cyclopts.types.ExistingBinPath

A Path that must exist and have extension bin.

alias of Annotated[Path, Parameter(validator=(Path(exists=True, file_okay=True, dir_okay=False, ext=('bin',)),))]

cyclopts.types.CsvPath

A Path that must have extension csv.

alias of Annotated[Path, Parameter(validator=(Path(exists=False, file_okay=True, dir_okay=False, ext=('csv',)),))]

cyclopts.types.ExistingCsvPath

A Path that must exist and have extension csv.

alias of Annotated[Path, Parameter(validator=(Path(exists=True, file_okay=True, dir_okay=False, ext=('csv',)),))]

cyclopts.types.TxtPath

A Path that must have extension txt.

alias of Annotated[Path, Parameter(validator=(Path(exists=False, file_okay=True, dir_okay=False, ext=('txt',)),))]

cyclopts.types.ExistingTxtPath

A Path that must exist and have extension txt.

alias of Annotated[Path, Parameter(validator=(Path(exists=True, file_okay=True, dir_okay=False, ext=('txt',)),))]

cyclopts.types.ImagePath

A Path that must have extension in {png, jpg, jpeg}.

alias of Annotated[Path, Parameter(validator=(Path(exists=False, file_okay=True, dir_okay=False, ext=('png', 'jpg', 'jpeg')),))]

cyclopts.types.ExistingImagePath

A Path that must exist and have extension in {png, jpg, jpeg}.

alias of Annotated[Path, Parameter(validator=(Path(exists=True, file_okay=True, dir_okay=False, ext=('png', 'jpg', 'jpeg')),))]

cyclopts.types.Mp4Path

A Path that must have extension mp4.

alias of Annotated[Path, Parameter(validator=(Path(exists=False, file_okay=True, dir_okay=False, ext=('mp4',)),))]

cyclopts.types.ExistingMp4Path

A Path that must exist and have extension mp4.

alias of Annotated[Path, Parameter(validator=(Path(exists=True, file_okay=True, dir_okay=False, ext=('mp4',)),))]

cyclopts.types.JsonPath

A Path that must have extension json.

alias of Annotated[Path, Parameter(validator=(Path(exists=False, file_okay=True, dir_okay=False, ext=('json',)),))]

cyclopts.types.ExistingJsonPath

A Path that must exist and have extension json.

alias of Annotated[Path, Parameter(validator=(Path(exists=True, file_okay=True, dir_okay=False, ext=('json',)),))]

cyclopts.types.TomlPath

A Path that must have extension toml.

alias of Annotated[Path, Parameter(validator=(Path(exists=False, file_okay=True, dir_okay=False, ext=('toml',)),))]

cyclopts.types.ExistingTomlPath

A Path that must exist and have extension toml.

alias of Annotated[Path, Parameter(validator=(Path(exists=True, file_okay=True, dir_okay=False, ext=('toml',)),))]

cyclopts.types.YamlPath

A Path that must have extension yaml.

alias of Annotated[Path, Parameter(validator=(Path(exists=False, file_okay=True, dir_okay=False, ext=('yaml',)),))]

cyclopts.types.ExistingYamlPath

A Path that must exist and have extension yaml.

alias of Annotated[Path, Parameter(validator=(Path(exists=True, file_okay=True, dir_okay=False, ext=('yaml',)),))]

Number

Annotated types for checking common int/float value constraints. All of these types will also work on sequence of numbers (e.g. tuple[int, int] or list[float]).

cyclopts.types.PositiveFloat

A float that must be >0.

alias of Annotated[float, Parameter(validator=(Number(lt=None, lte=None, gt=0, gte=None, modulo=None),))]

cyclopts.types.NonNegativeFloat

A float that must be >=0.

alias of Annotated[float, Parameter(validator=(Number(lt=None, lte=None, gt=None, gte=0, modulo=None),))]

cyclopts.types.NegativeFloat

A float that must be <0.

alias of Annotated[float, Parameter(validator=(Number(lt=0, lte=None, gt=None, gte=None, modulo=None),))]

cyclopts.types.NonPositiveFloat

A float that must be <=0.

alias of Annotated[float, Parameter(validator=(Number(lt=None, lte=0, gt=None, gte=None, modulo=None),))]

cyclopts.types.PositiveInt

An int that must be >0.

alias of Annotated[int, Parameter(validator=(Number(lt=None, lte=None, gt=0, gte=None, modulo=None),))]

cyclopts.types.NonNegativeInt

An int that must be >=0.

alias of Annotated[int, Parameter(validator=(Number(lt=None, lte=None, gt=None, gte=0, modulo=None),))]

cyclopts.types.NegativeInt

An int that must be <0.

alias of Annotated[int, Parameter(validator=(Number(lt=0, lte=None, gt=None, gte=None, modulo=None),))]

cyclopts.types.NonPositiveInt

An int that must be <=0.

alias of Annotated[int, Parameter(validator=(Number(lt=None, lte=0, gt=None, gte=None, modulo=None),))]

cyclopts.types.UInt8

An unsigned 8-bit integer.

alias of Annotated[int, Parameter(validator=(Number(lt=None, lte=255, gt=None, gte=0, modulo=None),))]

cyclopts.types.Int8

A signed 8-bit integer.

alias of Annotated[int, Parameter(validator=(Number(lt=None, lte=127, gt=None, gte=-128, modulo=None),))]

cyclopts.types.UInt16

An unsigned 16-bit integer.

alias of Annotated[int, Parameter(validator=(Number(lt=None, lte=65535, gt=None, gte=0, modulo=None),))]

cyclopts.types.Int16

A signed 16-bit integer.

alias of Annotated[int, Parameter(validator=(Number(lt=None, lte=32767, gt=None, gte=-32768, modulo=None),))]

cyclopts.types.UInt32

An unsigned 32-bit integer.

alias of Annotated[int, Parameter(validator=(Number(lt=4294967296, lte=None, gt=None, gte=0, modulo=None),))]

cyclopts.types.Int32

A signed 32-bit integer.

alias of Annotated[int, Parameter(validator=(Number(lt=2147483648, lte=None, gt=None, gte=-2147483648, modulo=None),))]

cyclopts.types.UInt64

An unsigned 64-bit integer.

alias of Annotated[int, Parameter(validator=(Number(lt=18446744073709551616, lte=None, gt=None, gte=0, modulo=None),))]

cyclopts.types.Int64

A signed 64-bit integer.

alias of Annotated[int, Parameter(validator=(Number(lt=9223372036854775808, lte=None, gt=None, gte=-9223372036854775808, modulo=None),))]

Json

Annotated types for parsing a json-string from the CLI.

cyclopts.types.Json

Parse a json-string from the CLI.

Note: Since Cyclopts v3.6.0, all dataclass-like classes now natively attempt to parse json-strings, so practical use-case of this annotation is limited.

Usage example:

from cyclopts import App, types

app = App()

@app.default
def main(json: types.Json):
    print(json)

app()
$ my-script '{"foo": 1, "bar": 2}'
{'foo': 1, 'bar': 2}

Web

Annotated types for common web-related values.

cyclopts.types.Email

An email address string with simple validation.

cyclopts.types.Port

An int limited to range [0, 65535].

alias of Annotated[int, Parameter(validator=(Number(lt=None, lte=65535, gt=None, gte=0, modulo=None),))]

cyclopts.types.URL

A str URL string with some simple validation.

.. autodata:: cyclopts.types.URL

Config

Cyclopts has builtin configuration classes to be used with App.config for loading user-defined defaults in many common scenarios. All Cyclopts builtins index into the configuration file with the following rules:

  1. Apply root_keys (if provided) to enter the project's configuration namespace.

  2. Apply the command name(s) to enter the current command's configuration namespace.

  3. Apply each key/value pair if CLI arguments have not been provided for that parameter.

class cyclopts.config.Toml(path, root_keys: None | Any | Iterable[Any] = (), *, must_exist: bool = False, search_parents: bool = False, allow_unknown: bool = False, use_commands_as_keys: bool = True)

Automatically read configuration from Toml file.

path: str | pathlib.Path

Path to TOML configuration file.

root_keys: Iterable[str] = None

The key or sequence of keys that lead to the root configuration structure for this app. For example, if referencing a pyproject.toml, it is common to store all of your projects configuration under:

[tool.myproject]

So, your Cyclopts App should be configured as:

app = cyclopts.App(config=cyclopts.config.Toml("pyproject.toml", root_keys=("tool", "myproject")))
must_exist: bool = False

The configuration file MUST exist. Raises FileNotFoundError if it does not exist.

search_parents: bool = False

If path doesn't exist, iteratively search parenting directories for a same-named configuration file. Raises FileNotFoundError if no configuration file is found.

allow_unknown: bool = False

Allow for unknown keys. Otherwise, if an unknown key is provided, raises UnknownOptionError.

use_commands_as_keys: bool = True

Use the sequence of commands as keys into the configuration.

For example, the following CLI invocation:

$ python my-script.py my-command

Would search into ["my-command"] for values.

class cyclopts.config.Yaml(path, root_keys: None | Any | Iterable[Any] = (), *, must_exist: bool = False, search_parents: bool = False, allow_unknown: bool = False, use_commands_as_keys: bool = True)

Automatically read configuration from YAML file.

path: str | pathlib.Path

Path to YAML configuration file.

root_keys: Iterable[str] = None

The key or sequence of keys that lead to the root configuration structure for this app. For example, if referencing a common config.yaml that is shared with other applications, it is common to store your projects configuration under a key like myproject:.

Your Cyclopts App would be configured as:

app = cyclopts.App(config=cyclopts.config.Yaml("config.yaml", root_keys="myproject"))
must_exist: bool = False

The configuration file MUST exist. Raises FileNotFoundError if it does not exist.

search_parents: bool = False

If path doesn't exist, iteratively search parenting directories for a same-named configuration file. Raises FileNotFoundError if no configuration file is found.

allow_unknown: bool = False

Allow for unknown keys. Otherwise, if an unknown key is provided, raises UnknownOptionError.

use_commands_as_keys: bool = True

Use the sequence of commands as keys into the configuration.

For example, the following CLI invocation:

$ python my-script.py my-command

Would search into ["my-command"] for values.

class cyclopts.config.Json(path, root_keys: None | Any | Iterable[Any] = (), *, must_exist: bool = False, search_parents: bool = False, allow_unknown: bool = False, use_commands_as_keys: bool = True)

Automatically read configuration from Json file.

path: str | pathlib.Path

Path to JSON configuration file.

root_keys: Iterable[str] = None

The key or sequence of keys that lead to the root configuration structure for this app. For example, if referencing a common config.json that is shared with other applications, it is common to store your projects configuration under a key like "myproject":.

Your Cyclopts App would be configured as:

app = cyclopts.App(config=cyclopts.config.Json("config.json", root_keys="myproject"))
must_exist: bool = False

The configuration file MUST exist. Raises FileNotFoundError if it does not exist.

search_parents: bool = False

If path doesn't exist, iteratively search parenting directories for a same-named configuration file. Raises FileNotFoundError if no configuration file is found.

allow_unknown: bool = False

Allow for unknown keys. Otherwise, if an unknown key is provided, raises UnknownOptionError.

use_commands_as_keys: bool = True

Use the sequence of commands as keys into the configuration.

For example, the following CLI invocation:

$ python my-script.py my-command

Would search into ["my-command"] for values.

class cyclopts.config.Env(prefix: str = '', *, command: bool = True)

Automatically derive environment variable names to read configurations from.

For example, consider the following app:

import cyclopts

app = cyclopts.App(config=cyclopts.config.Env("MY_SCRIPT_"))

@app.command
def my_command(foo, bar):
    print(f"{foo=} {bar=}")

app()

If values for foo and bar are not supplied by the command line, the app will check the environment variables MY_SCRIPT_MY_COMMAND_FOO and MY_SCRIPT_MY_COMMAND_BAR, respectively:

$ python my_script.py my-command 1 2
foo=1 bar=2

$ export MY_SCRIPT_MY_COMMAND_FOO=100
$ python my_script.py my-command --bar=2
foo=100 bar=2
$ python my_script.py my-command 1 2
foo=1 bar=2
prefix: str = ""

String to prepend to all autogenerated environment variable names. Typically ends in _, and is something like MY_APP_.

command: bool = True

If True, add the command's name (uppercase) after prefix.

Exceptions

exception cyclopts.CycloptsError

Bases: Exception

Root exception for runtime errors.

As CycloptsErrors bubble up the Cyclopts call-stack, more information is added to it. Finally, format_cyclopts_error() formats the message nicely for the user.

msg: str | None

If set, override automatic message generation.

verbose: bool

More verbose error messages; aimed towards developers debugging their Cyclopts app. Defaults to False.

root_input_tokens: list[str] | None

The parsed CLI tokens that were initially fed into the App.

unused_tokens: list[str] | None

Leftover tokens after parsing is complete.

target: Callable | None

The python function associated with the command being parsed.

argument: Argument | None

Argument that was matched.

command_chain: Sequence[str] | None

List of command that lead to target.

app: App | None

The Cyclopts application itself.

console: Console | None

Rich console to display runtime errors.

exception cyclopts.ValidationError

Bases: CycloptsError

Validator function raised an exception.

exception_message: str

Parenting Assertion/Value/Type Error message.

group: Group | None

If a group validator caused the exception.

value: Any

Converted value that failed validation.

exception cyclopts.UnknownOptionError

Bases: CycloptsError

Unknown/unregistered option provided by the cli.

A nearest-neighbor parameter suggestion may be printed.

token: Token

Token without a matching parameter.

argument_collection: ArgumentCollection

Argument collection of plausible options.

exception cyclopts.CoercionError

Bases: CycloptsError

There was an error performing automatic type coercion.

token: Token | None

Input token that couldn't be coerced.

target_type: type | None

Intended type to coerce into.

exception cyclopts.InvalidCommandError

Bases: CycloptsError

CLI token combination did not yield a valid command.

msg: str | None

If set, override automatic message generation.

verbose: bool

More verbose error messages; aimed towards developers debugging their Cyclopts app. Defaults to False.

root_input_tokens: list[str] | None

The parsed CLI tokens that were initially fed into the App.

unused_tokens: list[str] | None

Leftover tokens after parsing is complete.

target: Callable | None

The python function associated with the command being parsed.

argument: 'Argument' | None

Argument that was matched.

command_chain: Sequence[str] | None

List of command that lead to target.

app: 'App' | None

The Cyclopts application itself.

console: 'Console' | None

Rich console to display runtime errors.

exception cyclopts.UnusedCliTokensError

Bases: CycloptsError

Not all CLI tokens were used as expected.

exception cyclopts.MissingArgumentError

Bases: CycloptsError

A required argument was not provided.

tokens_so_far: list[str]

If the matched parameter requires multiple tokens, these are the ones we have parsed so far.

exception cyclopts.RepeatArgumentError

Bases: CycloptsError

The same parameter has erroneously been specified multiple times.

token: Token

The repeated token.

exception cyclopts.MixedArgumentError

Bases: CycloptsError

Cannot supply keywords and non-keywords to the same argument.

exception cyclopts.CommandCollisionError

Bases: Exception

A command with the same name has already been registered to the app.

exception cyclopts.EditorError

Bases: Exception

Root editor-related error.

Root exception raised by all exceptions in edit().

exception cyclopts.EditorNotFoundError

Bases: EditorError

Could not find a valid text editor for :func`.edit`.

exception cyclopts.EditorDidNotSaveError

Bases: EditorError

User did not save upon exiting edit().

exception cyclopts.EditorDidNotChangeError

Bases: EditorError

User did not edit file contents in edit().