Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions tests/test_annotated.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import sys
from pathlib import Path

import typer
from typer.testing import CliRunner
from typing_extensions import Annotated
Expand Down Expand Up @@ -76,3 +79,22 @@ def cmd(force: Annotated[bool, typer.Option("--force")] = False):
result = runner.invoke(app, ["--force"])
assert result.exit_code == 0, result.output
assert "Forcing operation" in result.output


def test_annotated_custom_path():
app = typer.Typer()

class CustomPath(Path):
# Subclassing Path was not fully supported before 3.12
# https://docs.python.org/3.12/whatsnew/3.12.html
if sys.version_info < (3, 12):
_flavour = type(Path())._flavour

@app.command()
def custom_parser(
my_path: Annotated[CustomPath, typer.Argument(parser=CustomPath)],
):
assert isinstance(my_path, CustomPath)

result = runner.invoke(app, "/some/quirky/path/implementation")
assert result.exit_code == 0
4 changes: 3 additions & 1 deletion typer/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,9 @@ def determine_type_convertor(type_: Any) -> Optional[Callable[[Any], Any]]:

def param_path_convertor(value: Optional[str] = None) -> Optional[Path]:
if value is not None:
return Path(value)
# allow returning any subclass of Path created by an annotated parser without converting
# it back to a Path
return value if isinstance(value, Path) else Path(value)
return None


Expand Down
Loading