diff --git a/AUTHORS.txt b/AUTHORS.txt index 7342b78f..222d9c10 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -71,7 +71,7 @@ Code Contributors - Dhanraj E (@Dhanu-dynamic) - Charan Rathore (@charan-rathore) -- Abdullah Ahmed (@abdull-ah-med) (with OpenAI Codex assistance) +- Abdullah Ahmed (@abdull-ah-med) And a few more "anonymous" contributors. diff --git a/jedi/plugins/pytest.py b/jedi/plugins/pytest.py index edaab3a7..ac8c2952 100644 --- a/jedi/plugins/pytest.py +++ b/jedi/plugins/pytest.py @@ -2,7 +2,9 @@ import sys from typing import List from pathlib import Path +from jedi.inference.arguments import ValuesArguments from jedi.inference.cache import inference_state_method_cache +from jedi.inference.gradual.annotation import infer_return_types from jedi.inference.imports import goto_import, load_module_from_path from jedi.inference.filters import ParserTreeFilter from jedi.inference.base_value import NO_VALUES, ValueSet @@ -31,9 +33,20 @@ def execute(callback): def infer_anonymous_param(func): def get_returns(value): - # Async fixtures provide the awaited value, rather than a coroutine. - if (value.tree_node.annotation is not None - and value.tree_node.parent.type != 'async_funcdef'): + if value.tree_node.annotation is not None: + if value.tree_node.parent.type == 'async_funcdef': + # Async fixtures provide the awaited value, rather than a + # coroutine. The annotation of an async generator describes + # the iterator, so the value is what that iterator yields. + result = infer_return_types(value, ValuesArguments([])) + if value.as_context().is_generator(): + return ValueSet.from_sets( + lazy_value.infer() + for v in result + for lazy_value in v.iterate(is_async=True) + ) + return result + result = value.execute_with_values() if any(v.name.get_qualified_names(include_module_names=True) == ('typing', 'Generator') diff --git a/test/completion/pytest.py b/test/completion/pytest.py index d84ef58a..1e898136 100644 --- a/test/completion/pytest.py +++ b/test/completion/pytest.py @@ -1,4 +1,4 @@ -from typing import Generator +from typing import AsyncGenerator, Generator import pytest from pytest import fixture @@ -229,6 +229,16 @@ async def async_yield_fixture(): yield 1.0 +@pytest.fixture +async def async_annotated_opaque() -> int: + return opaque_value + + +@pytest.fixture +async def async_generator_annotated() -> AsyncGenerator[str, None]: + yield opaque_value + + #? ['async_fixture'] def test_async_fixture_completion(async_fixt pass @@ -243,6 +253,13 @@ def test_async_fixture_inference(async_fixture, async_annotated_fixture, async_y async_yield_fixture +def test_async_fixture_annotation(async_annotated_opaque, async_generator_annotated): + #? int() + async_annotated_opaque + #? str() + async_generator_annotated + + #! 30 ['def async_fixture'] def test_async_fixture_goto(async_fixture): pass