Honor return annotations of async pytest fixtures

Async fixtures skipped the annotation branch, so a `-> T` annotation was
ignored and only the body was inferred. Infer the annotation directly:
the awaited value for coroutines, and the yielded value for annotated
async generators. Add cases where the body is not inferable.

Also drop the tooling note from the AUTHORS entry.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Abdullah AhmedandClaude Sonnet 5.5 committed 2026-10-12 04:52:32 -04:00
1 parent d8efff8e30
commit 3f7e8adddc
3 files changed
+35 -5

No files matched your search

+1 -1
View File
@@ -71,7 +71,7 @@ Code Contributors
- Dhanraj E (@Dhanu-dynamic) <dhanraj@labs.digiscrypt.com>
- Charan Rathore (@charan-rathore)
- Abdullah Ahmed (@abdull-ah-med) (with OpenAI Codex assistance)
- Abdullah Ahmed (@abdull-ah-med)
And a few more "anonymous" contributors.
+16 -3
View File
@@ -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')
+18 -1
View File
@@ -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