Cyclopts v2 introduces many new features, and more robust handling of complicated applications.
Cyclopts v2 is *mostly* backwards compatible with v1. Most breaking changes fall under the "advanced users" category and can be fixed with minimal changes.
Features & Improvements
* [Command & Parameter Groups](https://cyclopts.readthedocs.io/en/latest/groups.html):
* Every command & parameter belongs to one-or-more groups now.
* The name of the group is the title of the panel it will show up in on the help-page.
* A group can have `converter` and `validator`:
* [New Group Validator: `cyclopts.validator.LimitedChoice`](https://cyclopts.readthedocs.io/en/latest/group_validators.html#limitedchoice):
* Allows for only a certain number of CLI specifications within the group.
* Default behavior is "mutually-exclusive" within the group.
* New default group assignment based on parameter positioning:
* Positional-only arguments now default to being parsed into the `App.group_arguments` group. This group defaults to `Group("Arguments")`.
* All other arguments now default to being parsed into the `App.group_parameters` group. This group defaults to `Group("Parameters")`.
* [Improved Pydantic `validate_call` support.](https://cyclopts.readthedocs.io/en/latest/pydantic.html)
* Commands can now be [hidden via `App.show=False`](https://cyclopts.readthedocs.io/en/latest/api.html#cyclopts.App.show). I.e. decorate a function with `app.command(show=False)`.
* A custom "usage" string can now be specified[ via `App.usage`](https://cyclopts.readthedocs.io/en/latest/api.html#cyclopts.App.usage).
* Improved default error messages by not allowing values that begin with a hyphen by default (and instead treating them as keyword options). [This is controlled with the new `Parameter.allow_leading_hyphen=False` field.](https://cyclopts.readthedocs.io/en/latest/api.html#cyclopts.Parameter.allow_leading_hyphen)
* Iterable types (e.g. `List`) now consume all remaining valid tokens, regardless if specified as positional or keyword.
* Untyped parameters' type is [now inferred from the non-None default value's type](https://cyclopts.readthedocs.io/en/latest/rules.html#no-hint). If `None` or no default is provided, falls back to `str`.
* The `int` coercion logic now accepts decimal numbers from the CLI. It will first `round`, then cast to an `int`.
* `cyclopts.convert` (previously `cyclopts.coerce`) [now takes an optional callable `converter`](https://cyclopts.readthedocs.io/en/latest/api.html#cyclopts.convert), allowing custom-converters to leverage `convert`'s list/tuple/etc parsing abilities, while leaving final element-conversion to a custom function.
* Introduce the following `Path` annotated types:
ExistingPath, ResolvedPath, ResolvedExistingPath, Directory, ExistingDirectory, ResolvedDirectory, ResolvedExistingDirectory, File, ExistingFile, ResolvedFile, ResolvedExistingFile
* Introduce the following `Number` annotated types:
PositiveFloat, NonNegativeFloat, NegativeFloat, NonPositiveFloat, PositiveInt, NonNegativeInt, NegativeInt, NonPositiveInt
Breaking Changes
Cyclopts v2 is *mostly* backwards compatible with v1. Most breaking changes fall under the "advanced users" category.
* The new `Parameter.allow_leading_hyphen=False` feature's default is **opposite of the default behavior in Cyclopts v1**. For most use-cases, the new behavior is better. This primarily impacts those using a [meta-app](https://cyclopts.readthedocs.io/en/latest/meta_app.html).
If using a meta-app, the signature should probably be updated to be like:
app.meta.default
def main(*tokens: Annotated[str, Parameter(show=False, allow_leading_hyphen=True)]):
...
* If `Parameter.allow_leading_hyphen==False`, Iterable types (e.g. `List`) now consume all remaining tokens until an option is reached.
* If `Parameter.allow_leading_hyphen==True`, Iterable types (e.g. `List`) now consume all remaining tokens.
* `Parameter.token_count` has been removed. The feature was kind of broken to begin with, and significantly increased code complexity. We can revisit this feature in the future if someone needs it.
* `App.help_title_commands` has been removed. Use the new `App.group_commands` feature to modify the default parameters help-page panel title. E.g. `app.group_commands = "My Different Commands Title"`
* `App.help_title_parameters` has been removed. Use the new `App.group_arguments` and `App.group_parameters` feature to modify the default parameters help-page panel title.
* Renamed `cyclopts.coerce` to `cyclopts.convert` for naming consistency.
* Untyped parameters' types are now inferred from the non-None default value's type. If the default is `None` or no default is provided, falls back to `str`. E.g.
old behavior
def foo(value = 5):
`value` would be interpreted as a string.
new behavior
def foo(value = 5):
`value` would be interpreted as a `int` because thats `type(5)`.
* The `Validator` and `Converter` protocols (type-hinting) have been removed and replaced with just `Callable`. The more-specific type-hinting made typical use-case a bit more tedious than it really needed to be.
* `create_bound_arguments` is no longer part of the public API.
Bug Fixes
* Allow explicit value setting of a positive boolean flag with an `=`. I.e. `--my-flag=True` or `--my-flag=false`.
* Fixed `cyclopts.validators.Path` error messages.
* `Path` validator now only checks if the path is a file/directory **if it exists**. Previously it would always try to check.
* Many, many, many more...
Special Thanks
Special thanks to ravencentric for user-testing and providing quick and useful feedback!