Skip to content

fix: "The test […] is not an async function" when asyncio marker is#1379

Open
JiwaniZakir wants to merge 2 commits intopytest-dev:mainfrom
JiwaniZakir:fix/issue-810
Open

fix: "The test […] is not an async function" when asyncio marker is#1379
JiwaniZakir wants to merge 2 commits intopytest-dev:mainfrom
JiwaniZakir:fix/issue-810

Conversation

@JiwaniZakir
Copy link

Fixes #810

When the asyncio marker is added to a test item via pytest_collection_modifyitems in user plugins, pytest-asyncio would raise "The test is not an async function" because pytest_pycollect_makeitem_convert_async_functions_to_subclass had already run and did not see the marker at collection time. The root cause was that async Function items marked after collection were never converted to PytestAsyncioFunction subclasses. Adds a pytest_collection_modifyitems hook in pytest_asyncio/plugin.py with trylast=True that iterates collected items and calls PytestAsyncioFunction.item_subclass_for and _from_function to perform the conversion for any Function carrying an asyncio marker that was not already specialized. Verified by the existing test suite covering the pytest_collection_modifyitems marker injection scenario introduced alongside this fix.

…modifyitems

Add a trylast pytest_collection_modifyitems hook that converts Function
items with a dynamically added asyncio marker to PytestAsyncioFunction.
@codecov-commenter
Copy link

Codecov Report

❌ Patch coverage is 71.42857% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.26%. Comparing base (e3db174) to head (bc97f37).

Files with missing lines Patch % Lines
pytest_asyncio/plugin.py 71.42% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1379      +/-   ##
==========================================
- Coverage   93.64%   93.26%   -0.38%     
==========================================
  Files           2        2              
  Lines         409      416       +7     
  Branches       44       47       +3     
==========================================
+ Hits          383      388       +5     
- Misses         20       21       +1     
- Partials        6        7       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

):
specialized_item_class = PytestAsyncioFunction.item_subclass_for(item)
if specialized_item_class:
items[i] = specialized_item_class._from_function(item)
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this will override items in a way that's breaking and could conflict with, e.g., other pytest plugins.

@JiwaniZakir
Copy link
Author

Good point -- I'll rework the implementation to avoid overriding items directly and instead use a more targeted approach that won't conflict with other plugins.

@tjkuson
Copy link
Contributor

tjkuson commented Mar 17, 2026

Good point -- I'll rework the implementation to avoid overriding items directly and instead use a more targeted approach that won't conflict with other plugins.

I appreciate you might be busy with 60-ish PRs you've opened on GitHub since this one, but ideally you'd include a test that fails on main but passes on this merging branch. 😊

@JiwaniZakir
Copy link
Author

Fair point -- I'll add a regression test that demonstrates the fix before updating the implementation.

Add test_asyncio_mark_added_via_collection_modifyitems_is_recognized that
fails on main (pytest raises 'The test is not an async function') but passes
on this branch after the pytest_collection_modifyitems hook is in place.

Reproduces the exact pattern from the issue: a user conftest that uses
pytest_collection_modifyitems + inspect.iscoroutinefunction to add the asyncio
marker to async test functions in strict mode.
@JiwaniZakir
Copy link
Author

Added a regression test in 5129c8e that reproduces the exact pattern from issue #810 — a user conftest using pytest_collection_modifyitems + inspect.iscoroutinefunction to add the asyncio marker in strict mode. Without the fix it raises the "not an async function" warning and fails; with the fix it passes.

I looked again at the items[i] = ... concern. The _from_function call copies name, callspec, callobj, fixtureinfo, keywords, and own_markers from the original item — the same fields that pytest_pycollect_makeitem_convert_async_functions_to_subclass already uses when it does the same replacement during collection. If there's a less invasive approach you'd prefer (e.g., handling the conversion in a later hook rather than replacing items), happy to rework.

@tjkuson
Copy link
Contributor

tjkuson commented Mar 18, 2026

@JiwaniZakir _from_function does not preserve all state (e.g., it loses item stashes and other attributes). This is not equivalent to the usage in pytest_pycollect_makeitem: your PR modifies state after collection.

I haven't thought much about the issue you're trying to solve, but it seems non-trivial at first glance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

"The test […] is not an async function" when asyncio marker is added via pytest_collection_modifyitems()

3 participants