Path Handling and Autocompletion
Typer provides specialized handling for filesystem paths by integrating Python's pathlib.Path with an internal TyperPath class. This implementation ensures that path validation is robust while maintaining compatibility with Typer's custom command-line autocompletion system.
The TyperPath Class
The TyperPath class, defined in typer/models.py, is a direct subclass of click.Path. Its primary purpose is to override the default autocompletion behavior of Click to ensure it does not conflict with Typer's own completion logic.
class TyperPath(click.Path):
# Overwrite Click's behaviour to be compatible with Typer's autocompletion system
def shell_complete(
self, ctx: click.Context, param: click.Parameter, incomplete: str
) -> list[click.shell_completion.CompletionItem]:
"""Return an empty list so that the autocompletion functionality
will work properly from the commandline.
"""
return []
By returning an empty list in shell_complete, TyperPath signals to the underlying shell completion mechanism that it should not use Click's built-in path completion. Instead, Typer's internal completion system takes over, providing a consistent experience across different shells and integration with other Typer features.
Automatic Path Mapping
Developers typically do not instantiate TyperPath directly. Instead, Typer's internal type resolution logic in typer/main.py automatically maps parameters to TyperPath when it detects path-related annotations or configurations.
In typer/main.py, the get_click_type function checks for pathlib.Path annotations or specific path attributes in the ParameterInfo (the metadata behind typer.Option and typer.Argument):
# From typer/main.py
elif (
annotation == Path
or parameter_info.allow_dash
or parameter_info.path_type
or parameter_info.resolve_path
):
return TyperPath(
exists=parameter_info.exists,
file_okay=parameter_info.file_okay,
dir_okay=parameter_info.dir_okay,
writable=parameter_info.writable,
readable=parameter_info.readable,
resolve_path=parameter_info.resolve_path,
allow_dash=parameter_info.allow_dash,
path_type=parameter_info.path_type,
)
Path Validation and Configuration
When using pathlib.Path, you can configure validation rules using typer.Option or typer.Argument. These configurations are passed directly to the TyperPath constructor, which leverages click.Path's validation logic.
Commonly used validation parameters include:
exists: IfTrue, the path must already exist on the filesystem.file_okay: IfTrue, the path can be a file.dir_okay: IfTrue, the path can be a directory.writable: IfTrue, the path must be writable.readable: IfTrue, the path must be readable.resolve_path: IfTrue, the path will be resolved to its absolute form (handling symlinks and..).allow_dash: IfTrue, allows a single dash-to represent standard input/output.
Example: Validating a Configuration File
The following example demonstrates how to use Annotated with pathlib.Path and typer.Option to enforce that a configuration parameter points to an existing, readable file.
from pathlib import Path
from typing import Annotated
import typer
app = typer.Typer()
@app.command()
def main(
config: Annotated[
Path,
typer.Option(
exists=True,
file_okay=True,
dir_okay=False,
writable=False,
readable=True,
resolve_path=True,
),
],
):
text = config.read_text()
print(f"Config file contents: {text}")
In this setup, Typer internally creates a TyperPath instance with the specified constraints. If a user provides a path that does not exist or is a directory, Typer (via Click) will automatically generate a descriptive error message and exit before the main function is executed.
Autocompletion Integration
The reason TyperPath overrides shell_complete is to facilitate Typer's advanced autocompletion. When a user hits Tab in their shell, Typer's completion logic (often triggered via a hidden _TYPER_COMPLETE environment variable) is invoked.
Because TyperPath.shell_complete returns an empty list, Click's default path completion is bypassed. This allows Typer to use its own get_param_completion logic (found in typer/main.py), which can handle custom autocompletion callbacks defined by the developer while still providing standard path completion where appropriate.
This architecture ensures that path handling remains a first-class citizen in Typer, benefiting from both the robust validation of click.Path and the flexible autocompletion system of Typer.