Skip to content
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

Make show toolbar callback function async/sync compatible. #2066

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

tim-schilling
Copy link
Member

Description

This checks if the SHOW_TOOLBAR_CALLBACK is a coroutine if we're in async mode and the reverse if it's not. It will automatically wrap the function with sync_to_async or async_to_sync when necessary.

Fixes #2061

Checklist:

  • I have added the relevant tests for this change.
  • I have added an item to the Pending section of docs/changes.rst.

tim-schilling and others added 2 commits January 29, 2025 19:34
This checks if the SHOW_TOOLBAR_CALLBACK is a coroutine
if we're in async mode and the reverse if it's not. It
will automatically wrap the function with sync_to_async
or async_to_sync when necessary.
@adamantike
Copy link
Contributor

I can confirm these changes completely fix the issue reported in #2061, both when using a synchronous callback or an asynchronous one!

@elineda
Copy link
Member

elineda commented Feb 5, 2025

I understand the problem and this solution work.
BUT :D

I don't like very much to for the use sync_to_async all the time. We lock in the thread the function and it's not, for me, a good practice.

  • I would like to create a setting: SHOW_ASYNC_TOOLBAR_CALLBACK
  • In the call we check before a SHOW_TOOLBAR_CALLBACK and if it's none check SHOW_ASYNC_TOOLBAR_CALLBACK with a decorator.
  • In the acall we check before a SHOW_ASYNC_TOOLBAR_CALLBACK and if it's none check SHOW_TOOLBAR_CALLBACK with a decorator.

We ask to dev to write a sync or/and async version of their function. And if they won't it will work. But we let the possibility to async dev to do what they want.

@tim-schilling
Copy link
Member Author

I don't like very much to for the use sync_to_async all the time

To be clear, if you're using a sync callback with async_mode=False, it doesn't wrap it. Similarly, if you're using an async callback with async_mode=True, it doesn't wrap it. It only wraps if the callback is written for the opposite of async_mode.

Is that what you understood @elineda?

@elineda
Copy link
Member

elineda commented Feb 5, 2025

I don't like very much to for the use sync_to_async all the time

To be clear, if you're using a sync callback with async_mode=False, it doesn't wrap it. Similarly, if you're using an async callback with async_mode=True, it doesn't wrap it. It only wraps if the callback is written for the opposite of async_mode.

Is that what you understood @elineda?

yeah I missed that. In that case we can't have both sync and async fonction in the same time, but for a dev dependencies I think it's ok.

ok for me

@@ -11,7 +11,7 @@ def require_show_toolbar(view):
def inner(request, *args, **kwargs):
from debug_toolbar.middleware import get_show_toolbar

show_toolbar = get_show_toolbar()
show_toolbar = get_show_toolbar(async_mode=False)
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't we pass async_mode based on the type of request WSGIRequest or ASGIRequest here ? I mean I am not sure whether require_show_toolbar would ever be exposed to a custom async view in async context or vice versa but this would save the conversion as it slows down the overall process. thoughts?

Copy link
Member Author

Choose a reason for hiding this comment

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

I was hoping require_show_toolbar was an undocumented API, but it is documented. Yes, we need to pass in a better value than always False. Good catch @salty-ivy!

It feels like we'd want async_mode defined by whether view is a coroutine though rather than based on WSGIRequest vs ASGIRequest. Not 100% sure though.

Copy link
Member

@salty-ivy salty-ivy Feb 5, 2025

Choose a reason for hiding this comment

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

It can possible break in a situation where everything is in async context
including show_toolbar call back and if I use require_show_toolbar on an async view it will forcefully convert it into a sync func and we would get into similar error given that require_show_toolbar is exposed to such conditions :D

Copy link
Member

Choose a reason for hiding this comment

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

It feels like we'd want async_mode defined by whether view is a coroutine though rather than based on WSGIRequest vs ASGIRequest. Not 100% sure though.

may be checking both but it seems like that would cause a rabbit hole : (

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh. I totally missed that this decorator needs to be async friendly.

Copy link
Member

Choose a reason for hiding this comment

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

It feels like we'd want async_mode defined by whether view is a coroutine though rather than based on WSGIRequest vs ASGIRequest. Not 100% sure though.

This is correct, we should check whether view is a coroutine or not since django also converts the request object based on that, just checked : D

Copy link
Member

Choose a reason for hiding this comment

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

yeah missed that too and yeah a iscoroutinefunction is the way other django decorator work.

@salty-ivy salty-ivy self-assigned this Feb 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Version 5.0 breaks show_toolbar callback accessing database
4 participants