Skip to content

Commit 3ed84db

Browse files
committed
Add thread_sensitive arg to ensure_async func
1 parent e32fc67 commit 3ed84db

File tree

6 files changed

+21
-10
lines changed

6 files changed

+21
-10
lines changed

docs/src/reference/components.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -409,11 +409,12 @@ Compatible with both [standard Django forms](https://docs.djangoproject.com/en/s
409409
| `#!python on_success` | `#!python AsyncFormEvent | SyncFormEvent | None` | A callback function that is called when the form is successfully submitted. | `#!python None` |
410410
| `#!python on_error` | `#!python AsyncFormEvent | SyncFormEvent | None` | A callback function that is called when the form submission fails. | `#!python None` |
411411
| `#!python on_receive_data` | `#!python AsyncFormEvent | SyncFormEvent | None` | A callback function that is called before newly submitted form data is rendered. | `#!python None` |
412-
| `#!python on_change` | `#!python AsyncFormEvent | SyncFormEvent | None` | A callback function that is called when the form is changed. | `#!python None` |
412+
| `#!python on_change` | `#!python AsyncFormEvent | SyncFormEvent | None` | A callback function that is called when a form field is modified by the user. | `#!python None` |
413413
| `#!python auto_save` | `#!python bool` | If `#!python True`, the form will automatically call `#!python save` on successful submission of a `#!python ModelForm`. This has no effect on regular `#!python Form` instances. | `#!python True` |
414414
| `#!python extra_props` | `#!python dict[str, Any] | None` | Additional properties to add to the `#!html <form>` element. | `#!python None` |
415415
| `#!python extra_transforms` | `#!python Sequence[Callable[[VdomDict], Any]] | None` | A list of functions that transforms the newly generated VDOM. The functions will be repeatedly called on each VDOM node. | `#!python None` |
416416
| `#!python form_template` | `#!python str | None` | The template to use for the form. If `#!python None`, Django's default template is used. | `#!python None` |
417+
| `#!python thread_sensitive` | `#!python bool` | Whether to run event callback functions in thread sensitive mode. This mode only applies to sync functions, and is turned on by default due to Django ORM limitations. | `#!python True` |
417418
| `#!python top_children` | `#!python Sequence[Any]` | Additional elements to add to the top of the form. | `#!python tuple` |
418419
| `#!python bottom_children` | `#!python Sequence[Any]` | Additional elements to add to the bottom of the form. | `#!python tuple` |
419420
| `#!python key` | `#!python Key | None` | A key to uniquely identify this component which is unique amongst a component's immediate siblings. | `#!python None` |

docs/src/reference/hooks.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ Query functions can be sync or async.
4646
| --- | --- | --- | --- |
4747
| `#!python query` | `#!python Callable[FuncParams, Awaitable[Inferred]] | Callable[FuncParams, Inferred]` | A function that executes a query and returns some data. | N/A |
4848
| `#!python kwargs` | `#!python dict[str, Any] | None` | Keyword arguments to passed into the `#!python query` function. | `#!python None` |
49-
| `#!python thread_sensitive` | `#!python bool` | Whether to run your query function in thread sensitive mode. This mode only applies to sync query functions, and is turned on by default due to Django ORM limitations. | `#!python True` |
49+
| `#!python thread_sensitive` | `#!python bool` | Whether to run your query function in thread sensitive mode. This setting only applies to sync functions, and is turned on by default due to Django ORM limitations. | `#!python True` |
5050
| `#!python postprocessor` | `#!python AsyncPostprocessor | SyncPostprocessor | None` | A callable that processes the query `#!python data` before it is returned. The first argument of postprocessor function must be the query `#!python data`. All proceeding arguments are optional `#!python postprocessor_kwargs`. This postprocessor function must return the modified `#!python data`. | `#!python None` |
5151
| `#!python postprocessor_kwargs` | `#!python dict[str, Any] | None` | Keyworded arguments passed into the `#!python postprocessor` function. | `#!python None` |
5252

@@ -188,7 +188,7 @@ Mutation functions can be sync or async.
188188
| Name | Type | Description | Default |
189189
| --- | --- | --- | --- |
190190
| `#!python mutation` | `#!python Callable[FuncParams, bool | None] | Callable[FuncParams, Awaitable[bool | None]]` | A callable that performs Django ORM create, update, or delete functionality. If this function returns `#!python False`, then your `#!python refetch` function will not be used. | N/A |
191-
| `#!python thread_sensitive` | `#!python bool` | Whether to run the mutation in thread sensitive mode. This mode only applies to sync mutation functions, and is turned on by default due to Django ORM limitations. | `#!python True` |
191+
| `#!python thread_sensitive` | `#!python bool` | Whether to run the mutation in thread sensitive mode. This setting only applies to sync functions, and is turned on by default due to Django ORM limitations. | `#!python True` |
192192
| `#!python refetch` | `#!python Callable[..., Any] | Sequence[Callable[..., Any]] | None` | A query function (the function you provide to your `#!python use_query` hook) or a sequence of query functions that need a `#!python refetch` if the mutation succeeds. This is useful for refreshing data after a mutation has been performed. | `#!python None` |
193193

194194
<font size="4">**Returns**</font>

src/reactpy_django/components.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ def django_form(
131131
extra_props: dict[str, Any] | None = None,
132132
extra_transforms: Sequence[Callable[[VdomDict], Any]] | None = None,
133133
form_template: str | None = None,
134+
thread_sensitive: bool = True,
134135
top_children: Sequence[Any] = (),
135136
bottom_children: Sequence[Any] = (),
136137
key: Key | None = None,
@@ -144,13 +145,16 @@ def django_form(
144145
on_success: A callback function that is called when the form is successfully submitted.
145146
on_error: A callback function that is called when the form submission fails.
146147
on_receive_data: A callback function that is called before newly submitted form data is rendered.
147-
on_change: A callback function that is called when the form is changed.
148+
on_change: A callback function that is called when a form field is modified by the user.
148149
auto_save: If `True`, the form will automatically call `save` on successful submission of \
149150
a `ModelForm`. This has no effect on regular `Form` instances.
150151
extra_props: Additional properties to add to the `html.form` element.
151152
extra_transforms: A list of functions that transforms the newly generated VDOM. \
152153
The functions will be repeatedly called on each VDOM node.
153154
form_template: The template to use for the form. If `None`, Django's default template is used.
155+
thread_sensitive: Whether to run event callback functions in thread sensitive mode. \
156+
This mode only applies to sync functions, and is turned on by default due to Django \
157+
ORM limitations.
154158
top_children: Additional elements to add to the top of the form.
155159
bottom_children: Additional elements to add to the bottom of the form.
156160
key: A key to uniquely identify this component which is unique amongst a component's \
@@ -167,6 +171,7 @@ def django_form(
167171
extra_props=extra_props or {},
168172
extra_transforms=extra_transforms or [],
169173
form_template=form_template,
174+
thread_sensitive=thread_sensitive,
170175
top_children=top_children,
171176
bottom_children=bottom_children,
172177
key=key,

src/reactpy_django/forms/components.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ def _django_form(
4343
extra_props: dict,
4444
extra_transforms: Sequence[Callable[[VdomDict], Any]],
4545
form_template: str | None,
46+
thread_sensitive: bool,
4647
top_children: Sequence,
4748
bottom_children: Sequence,
4849
):
@@ -80,9 +81,9 @@ async def render_form():
8081
await database_sync_to_async(initialized_form.full_clean)()
8182
success = not initialized_form.errors.as_data()
8283
if success and on_success:
83-
await ensure_async(on_success)(form_event)
84+
await ensure_async(on_success, thread_sensitive=thread_sensitive)(form_event)
8485
if not success and on_error:
85-
await ensure_async(on_error)(form_event)
86+
await ensure_async(on_error, thread_sensitive=thread_sensitive)(form_event)
8687
if success and auto_save and isinstance(initialized_form, ModelForm):
8788
await database_sync_to_async(initialized_form.save)()
8889
set_submitted_data(None)
@@ -103,15 +104,15 @@ async def on_submit_callback(new_data: dict[str, Any]):
103104
new_form_event = FormEventData(
104105
form=initialized_form, submitted_data=new_data, set_submitted_data=set_submitted_data
105106
)
106-
await ensure_async(on_receive_data)(new_form_event)
107+
await ensure_async(on_receive_data, thread_sensitive=thread_sensitive)(new_form_event)
107108

108109
if submitted_data != new_data:
109110
set_submitted_data(new_data)
110111

111112
async def _on_change(_event):
112113
"""Event that exist solely to allow the user to detect form changes."""
113114
if on_change:
114-
await ensure_async(on_change)(form_event)
115+
await ensure_async(on_change, thread_sensitive=thread_sensitive)(form_event)
115116

116117
if not rendered_form:
117118
return None

src/reactpy_django/hooks.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def use_query(
104104
Kwargs:
105105
kwargs: Keyword arguments to passed into the `query` function.
106106
thread_sensitive: Whether to run the query in thread sensitive mode. \
107-
This mode only applies to sync query functions, and is turned on by default \
107+
This setting only applies to sync functions, and is turned on by default \
108108
due to Django ORM limitations.
109109
postprocessor: A callable that processes the query `data` before it is returned. \
110110
The first argument of postprocessor function must be the query `data`. All \
@@ -219,7 +219,7 @@ def use_mutation(
219219
220220
Kwargs:
221221
thread_sensitive: Whether to run the mutation in thread sensitive mode. \
222-
This mode only applies to sync mutation functions, and is turned on by default \
222+
This setting only applies to sync functions, and is turned on by default \
223223
due to Django ORM limitations.
224224
refetch: A query function (the function you provide to your `use_query` \
225225
hook) or a sequence of query functions that need a `refetch` if the \

src/reactpy_django/utils.py

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from concurrent.futures import ThreadPoolExecutor
1212
from copy import deepcopy
1313
from fnmatch import fnmatch
14+
from functools import wraps
1415
from importlib import import_module
1516
from pathlib import Path
1617
from typing import TYPE_CHECKING, Any, Awaitable, Callable
@@ -47,6 +48,9 @@
4748
from django.views import View
4849
from reactpy.types import ComponentConstructor
4950

51+
from reactpy_django.types import FuncParams, Inferred
52+
53+
5054
_logger = logging.getLogger(__name__)
5155
_TAG_PATTERN = r"(?P<tag>component)"
5256
_PATH_PATTERN = r"""(?P<path>"[^"'\s]+"|'[^"'\s]+')"""

0 commit comments

Comments
 (0)