diff --git a/AUTHORS.txt b/AUTHORS.txt index 0c9f4cb7..7342b78f 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -71,6 +71,8 @@ Code Contributors - Dhanraj E (@Dhanu-dynamic) - Charan Rathore (@charan-rathore) +- Abdullah Ahmed (@abdull-ah-med) (with OpenAI Codex assistance) + And a few more "anonymous" contributors. Note: (@user) means a github user name. diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5ed0f90c..c8d5edf9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,7 @@ Changelog Unreleased ++++++++++ +- Complete, infer and navigate to asynchronous pytest fixtures - Avoid changing the global recursion limit 0.20.0 (2026-05-02) diff --git a/jedi/plugins/pytest.py b/jedi/plugins/pytest.py index f7e88d2c..edaab3a7 100644 --- a/jedi/plugins/pytest.py +++ b/jedi/plugins/pytest.py @@ -31,7 +31,9 @@ def execute(callback): def infer_anonymous_param(func): def get_returns(value): - if value.tree_node.annotation is not None: + # 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'): result = value.execute_with_values() if any(v.name.get_qualified_names(include_module_names=True) == ('typing', 'Generator') @@ -223,6 +225,8 @@ class FixtureFilter(ParserTreeFilter): if funcdef.type != "funcdef": return False decorated = funcdef.parent + if decorated.type == "async_funcdef": + decorated = decorated.parent if decorated.type != "decorated": return False decorators = decorated.children[0] diff --git a/test/completion/pytest.py b/test/completion/pytest.py index 1f52c4f2..d84ef58a 100644 --- a/test/completion/pytest.py +++ b/test/completion/pytest.py @@ -208,3 +208,41 @@ def bla(admin_u def bla(admin_user): pass + + +# ----------------- +# asynchronous fixtures +# ----------------- + +@pytest.fixture +async def async_fixture(): + return 1 + + +@pytest.fixture(scope='module') +async def async_annotated_fixture() -> str: + return '' + + +@fixture +async def async_yield_fixture(): + yield 1.0 + + +#? ['async_fixture'] +def test_async_fixture_completion(async_fixt + pass + + +def test_async_fixture_inference(async_fixture, async_annotated_fixture, async_yield_fixture): + #? int() + async_fixture + #? str() + async_annotated_fixture + #? float() + async_yield_fixture + + +#! 30 ['def async_fixture'] +def test_async_fixture_goto(async_fixture): + pass