# Getting Started

Cyclopts relies heavily on function parameter type hints. If you are new to type hints or need a refresher, checkout the mypy cheatsheet.

## A Basic Cyclopts Application

The most basic Cyclopts application is as follows:

    from cyclopts import App

    app = App()

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

    if __name__ == "__main__":
        app()

Save this as `main.py` and execute it to see:

    $ python main.py
    Hello World!

The `App` class offers various configuration options that we'll explore in more detail later. The `app` object has a decorator method, `default`, which registers a function as the default action. In this example, the `main` function is our default action, and is executed when no CLI command is provided.

## Function Arguments

Let's add some arguments to make this program a little more interesting.

    from cyclopts import App

    app = App()

    @app.default
    def main(name):
        print(f"Hello {name}!")

    if __name__ == "__main__":
        app()

Executing the script with the argument `Alice` produces the following:

    $ python main.py Alice
    Hello Alice!

Code explanation:

1. The function `main()` was registered to `app` as the default action.

2. Calling `app()` at the bottom triggers the app to begin parsing CLI inputs.

3. Cyclopts identifies `"Alice"` as a positional argument and matches it to the parameter `name`. In the absence of an explicit type hint, Cyclopts defaults to parsing the value as a `str`.

   Note

   Without a type annotation, Cyclopts will actually first attempt to use the type of the parameter's default value. If the parameter doesn't have a default value, it will then fallback to `str`. See Coercion Rules.

4. Cyclopts calls the registered default function `main("Alice")`, and the greeting is printed.

## Multiple Arguments

Extending the example, lets add more arguments and type hints:

    from cyclopts import App

    app = App()

    @app.default
    def main(name: str, count: int, formal: bool = False):
        for _ in range(count):
           if formal:
              print(f"Hello {name}!")
           else:
              print(f"Hey {name}!")

    if __name__ == "__main__":
        app()

    $ python main.py Alice 3
    Hey Alice!
    Hey Alice!
    Hey Alice!

    $ python main.py Alice 3 --formal
    Hello Alice!
    Hello Alice!
    Hello Alice!

The command line input `"3"` is converted to an integer because the parameter `count` has the type hint `int`. Boolean ( here, `--formal`) parameters are interpreted as flags. Cyclopts natively handles all python builtin types (and more!). Cyclopts adheres to Python's argument binding rules, allowing for both positional and keyword arguments. All of the following CLI invocations are equivalent:

    $ python main.py Alice 3                  # Supplying arguments positionally.
    $ python main.py --name Alice --count 3   # Supplying arguments via keywords.
    $ python main.py --name=Alice --count=3   # Using = for matching keywords to values is allowed.
    $ python main.py --count 3 --name=Alice   # Keyword order does not matter.
    $ python main.py Alice --count 3          # positional followed by keyword
    $ python main.py --count 3 Alice          # Keywords can come before positional if the keyword is later in the function signature.

Like calling functions in python, positional arguments cannot be specified after a prior argument in the function signature was specified via keyword. For example, you cannot supply the count value `"3"` positionally while the value for `name` is specified via keyword:

    # The following are NOT allowed.
    $ python main.py --name=Alice 3  # invalid python: main(name="Alice", 3)
    $ python main.py 3 --name=Alice  # invalid python: main(3, name="Alice")

## Adding a Help Page

All CLI apps need to have a help page explaining how to use the application. By default, Cyclopts adds the `--help` (and the shortform `-h`) commands to your CLI. We can add application-level help documentation when creating our `app`:

    from cyclopts import App

    app = App(help="Help string for this demo application.")

    @app.default
    def main(name: str, count: int):
        for _ in range(count):
            print(f"Hello {name}!")

    if __name__ == "__main__":
        app()

    $ python main.py --help
    Usage: main COMMAND [ARGS] [OPTIONS]

    Help string for this demo application.

    ╭─ Commands ──────────────────────────────────────────────────────────╮
    │ --help -h  Display this message and exit.                           │
    │ --version  Display application version.                             │
    ╰─────────────────────────────────────────────────────────────────────╯
    ╭─ Parameters ────────────────────────────────────────────────────────╮
    │ *  NAME --name    [required]                                        │
    │ *  COUNT --count  [required]                                        │
    ╰─────────────────────────────────────────────────────────────────────╯

Note

Help flags can be changed with `help_flags`.

Let's add some help documentation for our parameters. Cyclopts uses the function's docstring and can interpret ReST, Google, Numpydoc-style and Epydoc docstrings (shoutout to docstring_parser).

    from cyclopts import App

    app = App()

    @app.default
    def main(name: str, count: int):
        """Help string for this demo application.

        Parameters
        ----------
        name: str
            Name of the user to be greeted.
        count: int
            Number of times to greet.
        """
        for _ in range(count):
            print(f"Hello {name}!")

    if __name__ == "__main__":
        app()

    $ python main.py --help
    Usage: main COMMAND [ARGS] [OPTIONS]

    Help string for this demo application.

    ╭─ Commands ──────────────────────────────────────────────────────────╮
    │ --help -h  Display this message and exit.                           │
    │ --version  Display application version.                             │
    ╰─────────────────────────────────────────────────────────────────────╯
    ╭─ Parameters ────────────────────────────────────────────────────────╮
    │ *  NAME --name    Name of the user to be greeted. [required]        │
    │ *  COUNT --count  Number of times to greet. [required]              │
    ╰─────────────────────────────────────────────────────────────────────╯

Note

If `App.help` is not explicitly set, Cyclopts will fallback to the first line (short description) of the registered `@app.default` function's docstring.

## Run

An alternative, terser API is available for simple applications with a single command. The `run()` function takes in a single callable (usually a function) and runs it as a Cyclopts application.

    import cyclopts

    def main(name: str, count: int):
        for _ in range(count):
            print(f"Hello {name}!")

    if __name__ == "__main__":
        cyclopts.run(main)

The `run()` function is intentionally simple. If greater control is required, then use the conventional `App` interface.