# Migrating From Typer

Much of Cyclopts's syntax is Typer-inspired. Migrating from Typer should be pretty straightforward; it is recommended to first read the Getting Started and Commands sections. The below table offers a jumping off point for translating the various portions of the APIs. The Typer Comparison page also provides many examples comparing the APIs.

Typer-to-Cyclopts API Reference
Typer | Cyclopts | Notes
--- | --- | ---

`typer.Typer()`

`cyclopts.App()`

Same/similar fields:

  - `App.name` - Optional name of application or sub-command.

Cyclopts has more user-friendly default features:

  - Equivalent `no_args_is_help=True`.

  - Equivalent `pretty_exceptions_enable=False`.

`@app.command()` | `@app.command()` | In Cyclopts, `@app.command` always results in a command. To define an action when no command is provided, see `@app.default`.
`app.add_typer(...)()` | `app.command(...)()` | Sub applications and commands are registered the same way in Cyclopts.
`@app.callback()` | `@app.default()` `@app.meta.default()` | Typer's callback always executes before executing an app. If used to provide functionality when no command was specified from the CLI, then use `@app.default()`. Otherwise, checkout Cyclopt's Meta App.
`Annotated[..., typer.Argument(...)]` `Annotated[..., typer.Option(...)]` | `Annotated[..., cyclopts.Parameter(...)]` | In Cyclopts, Positional/Keyword arguments are determined from the function signature. Some of Typer's validation fields, like `exists` for `Path` types are handled in Cyclopts by explicit validators.

Cyclopts and Typer mostly handle type-hints the same way, but there are a few notable exceptions:

Typer-to-Cyclopts Type-Hints
Type Annotation | Notes
--- | ---
`Enum` | Compared to Typer, Cyclopts handles `Enum` lookups in the reverse direction. Frequently, `Literal` offers a more terse, intuitive choice option.
`Union` | Typer does not support type unions. Cyclopts does.

## General Steps

1. Add the following import: `from cyclopts import App, Parameter`.

2. Change `app = Typer(...)` to just `app = App()`. Revisit more advanced configuration later.

3. Remove all `@app.callback` stuff. Cyclopts already provides a good `--version` handler for you.

4. Replace all `Annotated[..., Argument/Option]` type-hints with `Annotated[..., Parameter()]`. If only supplying a `help` string, it's better to supply it via docstring.

5. Cyclopts has similar boolean-flag handling as Typer, but has different configuration parameters.

       #########
       # Typer #
       #########
       # Overriding the name results in no "False" flag generation.
       my_flag: Annotated[bool, Option("--my-custom-flag")]
       # However, it can be custom specified:
       my_flag: Annotated[bool, Option("--my-custom-flag/--disable-my-custom-flag")]

       ############
       # Cyclopts #
       ############
       # Overriding the name still results in "False" flag generation:
       #    --my-custom-flag --no-my-custom-flag
       my_flag: Annotated[bool, Parameter("--my-custom-flag")]
       # Negative flag generation can be disabled:
       #    --my-custom-flag
       my_flag: Annotated[bool, Parameter("--my-custom-flag", negative="")]
       # Or the prefix can be changed:
       #    --my-custom-flag --disable-my-custom-flag
       my_flag: Annotated[bool, Parameter("--my-custom-flag", negative_bool="--disable-")]

After the basic migration is done, it is recommended to read through the rest of Cyclopts's documentation to learn about some of the better functionality it has, which could result in cleaner, terser code.