Skip to content

🐛 Ensure that Optional[list] values work correctly with callbacks #1018

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
26 changes: 26 additions & 0 deletions tests/test_others.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,32 @@ def main(name: str = typer.Option(..., callback=name_callback)):
assert "value is: Camila" in result.stdout


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

def names_callback(ctx, param, values: typing.Optional[typing.List[str]]):
if values is None:
return values
return [value.upper() for value in values]

@app.command()
def main(
names: typing.Optional[typing.List[str]] = typer.Option(
None, "--name", callback=names_callback
),
):
if names is None:
print("Hello World")
else:
print(f"Hello {', '.join(names)}")

result = runner.invoke(app, ["--name", "Sideshow", "--name", "Bob"])
assert "Hello SIDESHOW, BOB" in result.stdout

result = runner.invoke(app, [])
assert "Hello World" in result.stdout


def test_completion_argument():
file_path = Path(__file__).parent / "assets/completion_argument.py"
result = subprocess.run(
Expand Down
8 changes: 4 additions & 4 deletions typer/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -640,10 +640,10 @@ def convertor(value: Any) -> Any:

def generate_list_convertor(
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
) -> Callable[[Optional[Sequence[Any]]], Optional[List[Any]]]:
def internal_convertor(value: Optional[Sequence[Any]]) -> Optional[List[Any]]:
if value is None or len(value) == 0:
return default_value
Comment on lines -643 to +646
Copy link
Member

@svlandeg svlandeg Dec 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed the check to be more extensive and return default_value any time that value is None or empty. This needed to be updated when fixing the type, or the linter would complain about value possible being None when running the list comprehension.

return [convertor(v) if convertor else v for v in value]

return internal_convertor
Expand Down
Loading