Again, that's how they work by default, and that's the convention in many CLI programs and systems.
But you can change that.
In fact, it's very common to have optionalCLI arguments, it's way more common than having requiredCLI options.
As an example of how it could be useful, let's see how the ls CLI program works.
fast βπ¬ If you just typels π¬ ls will "list" the files and directories in the current directorytyper tests README.md LICENSE
π¬ But it also receives an optional CLI argumentls ./tests/ π¬ And then ls will list the files and directories inside of that directory from the CLI argument__init__.py test_tutorial
Because we are using typer.Argument()Typer will know that this is a CLI argument (no matter if required or optional).
Tip
By using Optional your editor will be able to know that the value could be None, and will be able to warn you if you do something assuming it is a str that would break if it was None.
Check the help:
fast βπ¬ First check the helppython main.py --help Usage: main.py [OPTIONS] [NAME]
Notice that "Camila" here is an optional CLI argument, not a CLI option, because we didn't use something like "--name Camila", we just passed "Camila" directly to the program.
Alternative (old) typer.Argument() as the default valueΒΆ
Typer also supports another older alternative syntax for declaring CLI arguments with additional metadata.
Instead of using Annotated, you can use typer.Argument() as the default value:
Before, because name didn't have any default value it would be a required parameter for the Python function, in Python terms.
When using typer.Argument() as the default value Typer does the same and makes it a requiredCLI argument.
We changed it to:
name:str=typer.Argument()
But now as typer.Argument() is the "default value" of the function's parameter, it would mean that "it is no longer required" (in Python terms).
As we no longer have the Python function default value (or its absence) to tell if something is required or not and what is the default value, typer.Argument() receives a first parameter default that serves the same purpose of defining that default value, or making it required.
Not passing any value to the default argument is the same as marking it as required. But you can also explicitly mark it as required by passing ... as the default argument, passed to typer.Argument(default=...).
Because the first parameter passed to typer.Argument(default=None) (the new "default" value) is None, Typer knows that this is an optionalCLI argument, if no value is provided when calling it in the command line, it will have that default value of None.
The default argument is the first one, so it's possible that you see code that passes the value without explicitly using default=, like:
name:str=typer.Argument(...)
...or like:
name:str=typer.Argument(None)
...but again, try to use Annotated if possible, that way your code in terms of Python will mean the same thing as with Typer and you won't have to remember any of these details.