← 返回首页
gh-84753: Make inspect.iscoroutinefunction() work with AsyncMock by sileht · Pull Request #94050 · python/cpython · GitHub
Skip to content

Navigation Menu

Toggle navigation
Sign in
Appearance settings
Search or jump to...

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Include my email address so I can be contacted

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Resetting focus

gh-84753: Make inspect.iscoroutinefunction() work with AsyncMock#94050

Merged
ambv merged 2 commits into
python:mainfrom
sileht:iscoroutinefix
Jun 30, 2022
Merged

gh-84753: Make inspect.iscoroutinefunction() work with AsyncMock#94050
ambv merged 2 commits into
python:mainfrom
sileht:iscoroutinefix

Conversation

sileht commented Jun 21, 2022
edited by bedevere-bot
Loading

Copy link
Copy Markdown
Contributor

The inspect version was not working with unittest.mock.AsyncMock.

This change moves the asyncio fix for AsyncMock in inspect module and
make asyncio.iscoroutinefunction an alias of inspect.iscoroutinefunction.

sileht requested review from 1st1, asvetlov and cjw296 as code owners June 21, 2022 09:36

ghost commented Jun 21, 2022
edited by ghost
Loading

Copy link
Copy Markdown

All commit authors signed the Contributor License Agreement.

Copy link
Copy Markdown

Most changes to Python require a NEWS entry.

Please add it using the blurb_it web app or the blurb command-line tool.

sileht commented Jun 21, 2022

Copy link
Copy Markdown
Contributor Author

@vstinner Can you take a look?

Copy link
Copy Markdown
Contributor

this shouldn't be needed AsyncMock already sets

cpython/Lib/unittest/mock.py

Lines 2175 to 2178 in 5fcfdd8

code_mock = NonCallableMock(spec_set=CodeType)
code_mock.co_flags = inspect.CO_COROUTINE
self.__dict__['__code__'] = code_mock

Comment thread Lib/inspect.py Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality Hide comment

Why is this here instead of re-using asyncio.coroutines._is_coroutine?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality Hide comment

I moved it from asyncio to inspect as the code using it is now located in inspect module.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality Hide comment

_is_coroutine feels like a property of asyncio, not inspect. I think it should stay where it is.

sileht commented Jun 21, 2022

Copy link
Copy Markdown
Contributor Author

this shouldn't be needed AsyncMock already sets

cpython/Lib/unittest/mock.py

Lines 2175 to 2178 in 5fcfdd8

code_mock = NonCallableMock(spec_set=CodeType)
code_mock.co_flags = inspect.CO_COROUTINE
self.__dict__['__code__'] = code_mock

The test cases I added passed was passing for asyncio version, but was not for the inspect version. So something doesn't work as expected.

Copy link
Copy Markdown
Contributor

looks like this issue is because mock.AsyncMock() doesn't pass inspect.isfunction:

from unittest import mock import inspect m = mock.AsyncMock() with mock.patch("inspect.isfunction", new=lambda x: True): assert inspect.iscoroutinefunction(m)

Originally posted by @graingert in #84753 (comment)

graingert commented Jun 21, 2022
edited
Loading

Copy link
Copy Markdown
Contributor

Could CallableMixin mess about with __instancecheck__/__subclasscheck__/__class__ to pass isinstance(AsyncMock(), types.FunctionType)?

sileht commented Jun 24, 2022

Copy link
Copy Markdown
Contributor Author

Could CallableMixin mess about with __instancecheck__/__subclasscheck__/__class__ to pass isinstance(AsyncMock(), types.FunctionType)?

I tried but this doesn't seem to work, I suspect this fall in isinstance C optimisation and __instancecheck__ and friends are never called.

Copy link
Copy Markdown
Contributor

I'm relying on inspect.iscoroutinefunction to reveal things that really really are Coroutine Functions, partials or methods and asyncio.iscoroutinefunction to reveal things that are Duck typed as a Coroutine Function

sileht commented Jun 24, 2022

Copy link
Copy Markdown
Contributor Author

I'm relying on inspect.iscoroutinefunction to reveal things that really really are Coroutine Functions, partials or methods and asyncio.iscoroutinefunction to reveal things that are Duck typed as a Coroutine Function

According to the doc, the only difference is asyncio.iscoroutinefunction also works for deprecated generator based coroutine
This legacy coroutine will(have ?) be removed for 3.11, so now both functions should be the same.

sileht commented Jun 24, 2022
edited
Loading

Copy link
Copy Markdown
Contributor Author

But, I agree that my solution doesn't work. We should keep the _is_coroutine hack as-is until generated coroutine are removed and found another solution to make isfunction pass for AsyncMock().

sileht commented Jun 28, 2022

Copy link
Copy Markdown
Contributor Author

I found another solution, I think it's cleaner.

Comment thread Lib/test/test_inspect.py Outdated Show resolved Hide resolved
sileht force-pushed the iscoroutinefix branch 3 times, most recently from fe4fc4e to 970f727 Compare June 28, 2022 17:56
Comment thread Lib/inspect.py Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality Hide comment

Can you try to preserve current coding style? Return early with False if a condition is false? Pseudo-code:

if not isfunction(f): return False if not _signature_is_functionlike(f): return False return bool(f.__code__.co_flags & flag)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality Hide comment

done

15 hidden items Load more…
ambv changed the title gh-84753: make inspect.iscoroutinefunction() works with AsyncMock gh-84753: Make inspect.iscoroutinefunction() work with AsyncMock Jun 30, 2022
ambv added needs backport to 3.10 only security fixes needs backport to 3.11 only security fixes labels Jun 30, 2022
ambv merged commit 4261b6b into python:main Jun 30, 2022

Copy link
Copy Markdown
Contributor

Thanks @sileht for the PR, and @ambv for merging it 🌮🎉.. I'm working now to backport this PR to: 3.10, 3.11.
🐍🍒⛏🤖

miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Jun 30, 2022
pythonGH-94050) The inspect version was not working with unittest.mock.AsyncMock. The fix introduces special-casing of AsyncMock in `inspect.iscoroutinefunction` equivalent to the one performed in `asyncio.iscoroutinefunction`. Co-authored-by: Łukasz Langa <lukasz@langa.pl> (cherry picked from commit 4261b6b) Co-authored-by: Mehdi ABAAKOUK <sileht@sileht.net>

Copy link
Copy Markdown

GH-94460 is a backport of this pull request to the 3.11 branch.

bedevere-bot removed the needs backport to 3.11 only security fixes label Jun 30, 2022
miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Jun 30, 2022
pythonGH-94050) The inspect version was not working with unittest.mock.AsyncMock. The fix introduces special-casing of AsyncMock in `inspect.iscoroutinefunction` equivalent to the one performed in `asyncio.iscoroutinefunction`. Co-authored-by: Łukasz Langa <lukasz@langa.pl> (cherry picked from commit 4261b6b) Co-authored-by: Mehdi ABAAKOUK <sileht@sileht.net>
bedevere-bot removed the needs backport to 3.10 only security fixes label Jun 30, 2022

Copy link
Copy Markdown

GH-94461 is a backport of this pull request to the 3.10 branch.

sileht commented Jun 30, 2022

Copy link
Copy Markdown
Contributor Author

Thanks all! That was fast 🚀

ambv pushed a commit that referenced this pull request Jun 30, 2022
…94050) (GH-94461) The inspect version was not working with unittest.mock.AsyncMock. The fix introduces special-casing of AsyncMock in `inspect.iscoroutinefunction` equivalent to the one performed in `asyncio.iscoroutinefunction`. Co-authored-by: Łukasz Langa <lukasz@langa.pl> (cherry picked from commit 4261b6b) Co-authored-by: Mehdi ABAAKOUK <sileht@sileht.net>
ambv pushed a commit that referenced this pull request Jun 30, 2022
…94050) (GH-94460) The inspect version was not working with unittest.mock.AsyncMock. The fix introduces special-casing of AsyncMock in `inspect.iscoroutinefunction` equivalent to the one performed in `asyncio.iscoroutinefunction`. Co-authored-by: Łukasz Langa <lukasz@langa.pl> (cherry picked from commit 4261b6b) Co-authored-by: Mehdi ABAAKOUK <sileht@sileht.net>
ambv added a commit to ambv/cpython that referenced this pull request Jul 5, 2022
The wording used in pythonGH-94050 suggests narrower scope than what was actually implemented. This commit clarifies the full impact of pythonGH-94050 in the change log.

Copy link
Copy Markdown
Member

This change seems to have caused a regression reported in #96127

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
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.

9 participants

Footer

© 2026 GitHub, Inc.