diff --git a/docs/tutorial/multiple-values/multiple-options.md b/docs/tutorial/multiple-values/multiple-options.md
index 00754e93b4..d61bee1588 100644
--- a/docs/tutorial/multiple-values/multiple-options.md
+++ b/docs/tutorial/multiple-values/multiple-options.md
@@ -26,9 +26,10 @@ Check it:
```console
+// The default value is 'None'
$ python main.py
-No provided users
+No provided users (raw input = None)
Aborted!
// Now pass a user
diff --git a/docs_src/multiple_values/multiple_options/tutorial001.py b/docs_src/multiple_values/multiple_options/tutorial001.py
index 141e9aa1ce..bce2322915 100644
--- a/docs_src/multiple_values/multiple_options/tutorial001.py
+++ b/docs_src/multiple_values/multiple_options/tutorial001.py
@@ -5,7 +5,7 @@
def main(user: Optional[List[str]] = typer.Option(None)):
if not user:
- print("No provided users")
+ print(f"No provided users (raw input = {user})")
raise typer.Abort()
for u in user:
print(f"Processing user: {u}")
diff --git a/docs_src/multiple_values/multiple_options/tutorial001_an.py b/docs_src/multiple_values/multiple_options/tutorial001_an.py
index 68ad2519ea..3dd19d8f59 100644
--- a/docs_src/multiple_values/multiple_options/tutorial001_an.py
+++ b/docs_src/multiple_values/multiple_options/tutorial001_an.py
@@ -6,7 +6,7 @@
def main(user: Annotated[Optional[List[str]], typer.Option()] = None):
if not user:
- print("No provided users")
+ print(f"No provided users (raw input = {user})")
raise typer.Abort()
for u in user:
print(f"Processing user: {u}")
diff --git a/tests/test_tutorial/test_multiple_values/test_multiple_options/test_tutorial001.py b/tests/test_tutorial/test_multiple_values/test_multiple_options/test_tutorial001.py
index 3c57bfd33e..4293ed8d3d 100644
--- a/tests/test_tutorial/test_multiple_values/test_multiple_options/test_tutorial001.py
+++ b/tests/test_tutorial/test_multiple_values/test_multiple_options/test_tutorial001.py
@@ -15,6 +15,7 @@ def test_main():
result = runner.invoke(app)
assert result.exit_code != 0
assert "No provided users" in result.output
+ assert "raw input = None" in result.output
assert "Aborted" in result.output
diff --git a/tests/test_tutorial/test_multiple_values/test_multiple_options/test_tutorial001_an.py b/tests/test_tutorial/test_multiple_values/test_multiple_options/test_tutorial001_an.py
index 0009fd2f05..20ea235307 100644
--- a/tests/test_tutorial/test_multiple_values/test_multiple_options/test_tutorial001_an.py
+++ b/tests/test_tutorial/test_multiple_values/test_multiple_options/test_tutorial001_an.py
@@ -15,6 +15,7 @@ def test_main():
result = runner.invoke(app)
assert result.exit_code != 0
assert "No provided users" in result.output
+ assert "raw input = None" in result.output
assert "Aborted" in result.output
diff --git a/typer/main.py b/typer/main.py
index c739a293ae..21683d913a 100644
--- a/typer/main.py
+++ b/typer/main.py
@@ -631,9 +631,11 @@ def convertor(value: Any) -> Any:
def generate_list_convertor(
- convertor: Optional[Callable[[Any], Any]]
-) -> Callable[[Sequence[Any]], List[Any]]:
- def internal_convertor(value: Sequence[Any]) -> List[Any]:
+ convertor: Optional[Callable[[Any], Any]], default_value: Optional[Any]
+) -> Callable[[Sequence[Any]], Optional[List[Any]]]:
+ def internal_convertor(value: Sequence[Any]) -> Optional[List[Any]]:
+ if default_value is None and len(value) == 0:
+ return None
return [convertor(v) if convertor else v for v in value]
return internal_convertor
@@ -852,7 +854,9 @@ def get_click_param(
)
convertor = determine_type_convertor(main_type)
if is_list:
- convertor = generate_list_convertor(convertor)
+ convertor = generate_list_convertor(
+ convertor=convertor, default_value=default_value
+ )
if is_tuple:
convertor = generate_tuple_convertor(main_type.__args__)
if isinstance(parameter_info, OptionInfo):