-
-
Notifications
You must be signed in to change notification settings - Fork 543
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use the correct iscoroutinefunction function for python 3.12+ #3599
Use the correct iscoroutinefunction function for python 3.12+ #3599
Conversation
Reviewer's Guide by SourceryThis pull request addresses a bug where custom resolvers with permission_classes were not accepting the @sync_to_async decorator. The fix involves modifying the is_async property in the resolver class to correctly identify functions decorated with @sync_to_async as asynchronous. Additionally, a new test case has been added to verify the fix, and a release note has been created. File-Level Changes
Tips
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @shmoon-kr - I've reviewed your changes and they look great!
Here's what I looked at during the review
- 🟡 General issues: 1 issue found
- 🟢 Security: all looks good
- 🟢 Testing: all looks good
- 🟢 Complexity: all looks good
- 🟡 Documentation: 1 issue found
Help me be more useful! Please click 👍 or 👎 on each comment to tell me if it was helpful.
RELEASE.md
Outdated
@@ -0,0 +1,4 @@ | |||
Release type: patch | |||
|
|||
Fix a bug "a custom resolver with permission_classes doesn't accept @sync_to_async decorator" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (documentation): Consider using consistent quotation marks.
Single quotes are often preferred in markdown files for consistency.
Thanks for adding the Here's a preview of the changelog: Fix an issue where The root cause is that in python >= 3.12 coroutine functions are market using Here's the tweet text:
|
Thanks for adding the Here's a preview of the changelog: Fix a bug "a custom resolver with permission_classes doesn't accept @sync_to_async decorator" Here's the tweet text:
|
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3599 +/- ##
==========================================
- Coverage 96.82% 96.82% -0.01%
==========================================
Files 514 514
Lines 33293 33322 +29
Branches 5522 5528 +6
==========================================
+ Hits 32236 32264 +28
- Misses 833 834 +1
Partials 224 224 |
CodSpeed Performance ReportMerging #3599 will not alter performanceComparing Summary
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your PR and investigation. I have some comments, please let me know what you think 😊
strawberry/types/fields/resolver.py
Outdated
return ( | ||
isinstance(self._unbound_wrapped_func, SyncToAsync) | ||
or iscoroutinefunction(self._unbound_wrapped_func) | ||
or isasyncgenfunction(self._unbound_wrapped_func) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to avoid importing somewhat django-specific projects like asgiref into strawberry core components.
Do we have a different way to identify SyncToAsync as a coroutinefunction?
@bellini666 I thought you recently PR'd the asyncio.coroutime marker to SyncToAsync.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about using asyncio.iscoroutinefunction() instead of inspect.iscoroutinefunction()? It was said that asyncio.iscoroutinefunction() function does two tests; it uses inspect.iscoroutinefunction() first, and if that test fails tests if the function is a function with the @acyncio.coroutine decorator applied. (https://stackoverflow.com/questions/36076619/test-if-function-or-method-is-normal-or-asynchronous)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@erikwrede it was there already, what I PR'd there was a performance improvement: django/asgiref#390 =P
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@shmoon-kr sounds good!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bellini666 oops the diff fooled me haha
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Request for changes is mostly for the issue I commented with python 3.12+
Other than that, looking good! :)
strawberry/types/fields/resolver.py
Outdated
@@ -3,8 +3,9 @@ | |||
import inspect | |||
import sys | |||
import warnings | |||
from asyncio import iscoroutinefunction |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will not work for python 3.12
Check here how asgiref does to support this for both 3.12 and older versions.
You can probably copy the:
if hasattr(inspect, "markcoroutinefunction"):
iscoroutinefunction = inspect.iscoroutinefunction
else:
iscoroutinefunction = asyncio.iscoroutinefunction
In here and use it
tests/types/test_resolver_types.py
Outdated
@@ -94,3 +96,12 @@ def get_overlap() -> Union[Venn, Diagram]: ... | |||
|
|||
resolver = StrawberryResolver(get_overlap) | |||
assert resolver.type == Union[Venn, Diagram] | |||
|
|||
|
|||
def test_async_resolver(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe naming it more close to what it is testing?
def test_async_resolver(): | |
def test_sync_to_async_resolver(): |
@bellini666 Thanks for a comment. I updated the PR based on your suggestion. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the adjustments :)
Left some extra nits and this should be good to go.
Now, not sure why some unrelated tests are broken. @patrick91 , any idea?
strawberry/types/fields/resolver.py
Outdated
if hasattr(inspect, "markcoroutinefunction"): | ||
iscoroutinefunction = inspect.iscoroutinefunction | ||
else: | ||
iscoroutinefunction = asyncio.iscoroutinefunction |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I would define this at module level
Also, maybe add a comment to why this is being done. I know why, but someone checking this hasattr(inspect, "markcoroutinefunction")
to define iscoroutinefunction
could get confused
RELEASE.md
Outdated
Release type: patch | ||
|
||
Fix a bug "a custom resolver with permission_classes doesn't accept @sync_to_async decorator" | ||
The root cause was inspect.iscoroutinefunction() function returns True only for functions defined with "async def". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably this needs to be updated after the change I requested? As this is still going to be used for python 3.12+ (but it actually works in there)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some more nits
(sorry for the trouble 😅)
RELEASE.md
Outdated
@@ -0,0 +1,4 @@ | |||
Release type: patch | |||
|
|||
Fix a bug ''a custom resolver with permission_classes doesn't accept @sync_to_async decorator" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix a bug ''a custom resolver with permission_classes doesn't accept @sync_to_async decorator" | |
Fix a bug "a custom resolver with permission_classes doesn't accept @sync_to_async decorator" |
also this seems weirdly written... maybe "fix a bug where doing X would raise an issue Y" or something? not really sure as I'm usually very bad at this =P
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bellini666 I modified the release note again. "Fix a bug "StrawberryResolver.is_async returns False for a function decorated by @sync_to_async" I believe this phrase, although not the best, clearly expresses the revisions.
strawberry/types/fields/resolver.py
Outdated
@@ -171,6 +172,12 @@ def is_reserved_type(self, other: builtins.type) -> bool: | |||
|
|||
T = TypeVar("T") | |||
|
|||
# asyncio.iscoroutinefunction was deprecated in python >= 3.12 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is not that it was deprecated, but actually that python 3.12 changed the way to mark something as a coroutine by requiring it to be marked using inspect.markcoroutinefunction, and that needs to be checked with inspect.iscoroutinefunction instead of the one from asyncio
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bellini666 I find it difficult to explain this situation easily and clearly. The official document states, "inspect.iscoroutinefunction(object) Changed in version 3.12: Sync functions marked with markcoroutinefunction() now return True." I am considering noting this as a comment verbatim. How about this idea?
… return True for @sync_to_async functions
for more information, see https://pre-commit.ci
fa7e98a
to
c8962df
Compare
Thanks for contributing to Strawberry! 🎉 You've been invited to join You can also request a free sticker by filling this form: https://forms.gle/dmnfQUPoY5gZbVT67 And don't forget to join our discord server: https://strawberry.rocks/discord 🔥 |
Description
Fix a bug "a custom resolver with permission_classes doesn't accept @sync_to_async decorator"
The root cause was inspect.iscoroutinefunction() function returns True only for functions defined with "async def".
Now is_async function returns True for a resolver function decorated with @sync_to_async
Types of Changes
Issues Fixed or Closed by This PR
Checklist
Summary by Sourcery
Fix the issue where custom resolvers with permission_classes did not work with the @sync_to_async decorator by updating the is_async function to recognize SyncToAsync instances.
Bug Fixes:
Documentation:
Tests: