You can declare a CLI parameter to be a standard Python pathlib.Path.
This is what you would do for directory paths, file paths, etc:
frompathlibimportPathfromtypingimportOptionalimporttyperfromtyping_extensionsimportAnnotateddefmain(config:Annotated[Optional[Path],typer.Option()]=None):ifconfigisNone:print("No config file")raisetyper.Abort()ifconfig.is_file():text=config.read_text()print(f"Config file contents: {text}")elifconfig.is_dir():print("Config is a directory, will use all its config files")elifnotconfig.exists():print("The config doesn't exist")if__name__=="__main__":typer.run(main)
Tip
Prefer to use the Annotated version if possible.
frompathlibimportPathfromtypingimportOptionalimporttyperdefmain(config:Optional[Path]=typer.Option(None)):ifconfigisNone:print("No config file")raisetyper.Abort()ifconfig.is_file():text=config.read_text()print(f"Config file contents: {text}")elifconfig.is_dir():print("Config is a directory, will use all its config files")elifnotconfig.exists():print("The config doesn't exist")if__name__=="__main__":typer.run(main)
And again, as you receive a standard Python Path object the same as the type annotation, your editor will give you autocompletion for all its attributes and methods.
Check it:
fast βπ¬ No configpython main.py No config file Aborted!
π¬ Pass a config that doesn't existpython main.py --config config.txt The config doesn't exist
π¬ Now create a quick configecho "some settings" > config.txt π¬ And try againpython main.py --config config.txt Config file contents: some settings
π¬ And with a directorypython main.py --config ./ Config is a directory, will use all its config files
You can perform several validations for PathCLI parameters:
exists: if set to true, the file or directory needs to exist for this value to be valid. If this is not required and a file does indeed not exist, then all further checks are silently skipped.
file_okay: controls if a file is a possible value.
dir_okay: controls if a directory is a possible value.
writable: if true, a writable check is performed.
readable: if true, a readable check is performed.
resolve_path: if this is true, then the path is fully resolved before the value is passed onwards. This means that itβs absolute and symlinks are resolved.
Technical Details
It will not expand a tilde-prefix (something with ~, like ~/Documents/), as this is supposed to be done by the shell only.
You probably won't need these configurations at first, you may want to skip it.
They are used for more advanced use cases.
allow_dash: If this is set to True, a single dash to indicate standard streams is permitted.
path_type: optionally a string type that should be used to represent the path. The default is None which means the return value will be either bytes or unicode depending on what makes most sense given the input data Click deals with.