Skip to content
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

🐛 Fix evaluating stringified annotations in Python 3.10 (also from __future__ import annotations) #721

Merged
merged 4 commits into from Mar 23, 2024
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 19 additions & 0 deletions tests/test_annotated.py
Expand Up @@ -2,6 +2,8 @@
from typer.testing import CliRunner
from typing_extensions import Annotated

from .utils import needs_py310

runner = CliRunner()


Expand All @@ -21,6 +23,23 @@ def cmd(val: Annotated[int, typer.Argument()] = 0):
assert "hello 42" in result.output


@needs_py310
def test_annotated_argument_in_string_type_with_default():
app = typer.Typer()

@app.command()
def cmd(val: "Annotated[int, typer.Argument()]" = 0):
print(f"hello {val}")

result = runner.invoke(app)
assert result.exit_code == 0, result.output
assert "hello 0" in result.output

result = runner.invoke(app, ["42"])
assert result.exit_code == 0, result.output
assert "hello 42" in result.output


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

Expand Down
7 changes: 7 additions & 0 deletions tests/utils.py
@@ -0,0 +1,7 @@
import sys

import pytest

needs_py310 = pytest.mark.skipif(
sys.version_info < (3, 10), reason="requires python3.10+"
)
7 changes: 6 additions & 1 deletion typer/utils.py
@@ -1,4 +1,5 @@
import inspect
import sys
from copy import copy
from typing import Any, Callable, Dict, List, Tuple, Type, cast, get_type_hints

Expand Down Expand Up @@ -106,7 +107,11 @@ def _split_annotation_from_typer_annotations(


def get_params_from_function(func: Callable[..., Any]) -> Dict[str, ParamMeta]:
signature = inspect.signature(func)
if sys.version_info >= (3, 10):
signature = inspect.signature(func, eval_str=True)
else:
signature = inspect.signature(func)

type_hints = get_type_hints(func)
params = {}
for param in signature.parameters.values():
Expand Down