# 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.

    - For booleans, defaults to `no-{name}` (see `negative_bool`).

    - For iterables, defaults to `empty-{name}` (see `negative_iterable`).

    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:

    - EditorError -- Base editor error exception. Explicitly raised if editor subcommand returned a non-zero exit code.

    - EditorNotFoundError -- A suitable text editor could not be found.

    - EditorDidNotSaveError -- The user exited the text-editor without saving and `save=True`.

    - EditorDidNotChangeError -- The user did not change the file contents and `required=True`.

  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()`.