Skip to content

Commit 0128169

Browse files
committed
Typehints, Postprocessor returns Any, and defaults configuration value for postprocessor
1 parent 03c0681 commit 0128169

File tree

7 files changed

+41
-20
lines changed

7 files changed

+41
-20
lines changed

docs/src/features/hooks.md

+2-4
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ The function you provide into this hook must return either a `Model` or `QuerySe
103103
1. Want to use this hook to defer IO intensive tasks to be computed in the background
104104
2. Want to to utilize `use_query` with a different ORM
105105

106-
... then you can disable all postprocessing behavior by modifying the `QueryOptions.postprocessor` parameter. In the example below, we will set the `postprocessor` to a function that takes one argument and returns `None`.
106+
... then you can disable all postprocessing behavior by modifying the `QueryOptions.postprocessor` parameter. In the example below, we will set the `postprocessor` to `None`.
107107

108108
=== "components.py"
109109

@@ -118,10 +118,8 @@ The function you provide into this hook must return either a `Model` or `QuerySe
118118

119119
@component
120120
def todo_list():
121-
# By setting the postprocessor to a function that takes one argument
122-
# and returns None, we can disable postprocessing behavior.
123121
query = use_query(
124-
QueryOptions(postprocessor=lambda data: None),
122+
QueryOptions(postprocessor=None),
125123
execute_io_intensive_operation,
126124
)
127125

docs/src/features/settings.md

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020

2121
# The URL for IDOM to serve websockets
2222
IDOM_WEBSOCKET_URL = "idom/"
23+
24+
# Dotted path to the default postprocessor function, or `None`
25+
IDOM_DEFAULT_QUERY_POSTPROCESSOR = "example_project.utils.my_postprocessor"
2326
```
2427

2528
<!--settings-end-->

src/django_idom/config.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
from django.core.cache import DEFAULT_CACHE_ALIAS, BaseCache, caches
55
from idom.core.types import ComponentConstructor
66

7-
from django_idom.types import ViewComponentIframe
7+
from django_idom.defaults import _DEFAULT_QUERY_POSTPROCESSOR
8+
from django_idom.types import Postprocessor, ViewComponentIframe
89

910

1011
IDOM_REGISTERED_COMPONENTS: Dict[str, ComponentConstructor] = {}
@@ -14,6 +15,7 @@
1415
IDOM_WS_MAX_RECONNECT_TIMEOUT = getattr(
1516
settings, "IDOM_WS_MAX_RECONNECT_TIMEOUT", 604800
1617
)
18+
IDOM_DEFAULT_QUERY_POSTPROCESSOR: Postprocessor | None = _DEFAULT_QUERY_POSTPROCESSOR
1719

1820
# Determine if using Django caching or LRU cache
1921
IDOM_CACHE: BaseCache = (

src/django_idom/defaults.py

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from __future__ import annotations
2+
3+
from typing import Any, Callable
4+
5+
from django.conf import settings
6+
7+
from django_idom.utils import _import_dotted_path
8+
9+
10+
_DEFAULT_QUERY_POSTPROCESSOR: Callable[..., Any] | None = _import_dotted_path(
11+
getattr(
12+
settings,
13+
"IDOM_DEFAULT_QUERY_POSTPROCESSOR",
14+
"django_idom.utils.django_query_postprocessor",
15+
)
16+
)

src/django_idom/hooks.py

+2-8
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
_Params,
2727
_Result,
2828
)
29-
from django_idom.utils import _generate_obj_name, django_query_postprocessor
29+
from django_idom.utils import _generate_obj_name
3030

3131

3232
_logger = logging.getLogger(__name__)
@@ -155,17 +155,11 @@ def execute_query() -> None:
155155
# Run the initial query
156156
new_data = query(*args, **kwargs)
157157

158-
# Use a custom postprocessor, if provided
159158
if query_options.postprocessor:
160-
query_options.postprocessor(
159+
new_data = query_options.postprocessor(
161160
new_data, **query_options.postprocessor_kwargs
162161
)
163162

164-
# Use the default postprocessor
165-
else:
166-
django_query_postprocessor(
167-
new_data, **query_options.postprocessor_kwargs
168-
)
169163
except Exception as e:
170164
set_data(None)
171165
set_loading(False)

src/django_idom/types.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
from django.views.generic import View
1919
from typing_extensions import ParamSpec
2020

21+
from django_idom.defaults import _DEFAULT_QUERY_POSTPROCESSOR
22+
2123

2224
__all__ = ["_Result", "_Params", "_Data", "IdomWebsocket", "Query", "Mutation"]
2325

@@ -64,16 +66,20 @@ class ViewComponentIframe:
6466

6567

6668
class Postprocessor(Protocol):
67-
def __call__(self, data: Any, **kwargs: Any) -> None:
69+
def __call__(self, data: Any) -> Any:
6870
...
6971

7072

7173
@dataclass
7274
class QueryOptions:
7375
"""Configuration options that can be provided to `use_query`."""
7476

75-
postprocessor: Postprocessor | None = None
76-
"""A post processing callable that can read/modify the query `data`.
77+
postprocessor: Postprocessor | None = _DEFAULT_QUERY_POSTPROCESSOR
78+
"""A callable that can modify the query `data` after the query has been executed.
79+
80+
The first argument of postprocessor must be the query `data`. All proceeding arguments
81+
are optional `postprocessor_kwargs` (see below). This postprocessor function must return
82+
the modified `data`.
7783
7884
If `None`, the default postprocessor is used.
7985

src/django_idom/utils.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919
from django.utils.encoding import smart_str
2020
from django.views import View
2121

22-
from django_idom.config import IDOM_REGISTERED_COMPONENTS
23-
2422

2523
_logger = logging.getLogger(__name__)
2624
_component_tag = r"(?P<tag>component)"
@@ -77,6 +75,8 @@ async def render_view(
7775

7876

7977
def _register_component(dotted_path: str) -> None:
78+
from django_idom.config import IDOM_REGISTERED_COMPONENTS
79+
8080
if dotted_path in IDOM_REGISTERED_COMPONENTS:
8181
return
8282

@@ -206,8 +206,8 @@ def _generate_obj_name(object: Any) -> str | None:
206206

207207

208208
def django_query_postprocessor(
209-
data: QuerySet | Model, /, many_to_many: bool = True, many_to_one: bool = True
210-
) -> None:
209+
data: QuerySet | Model, many_to_many: bool = True, many_to_one: bool = True
210+
) -> QuerySet | Model:
211211
"""Recursively fetch all fields within a `Model` or `QuerySet` to ensure they are not performed lazily.
212212
213213
Some behaviors can be modified through `query_options` attributes."""
@@ -254,3 +254,5 @@ def django_query_postprocessor(
254254
" - You are attempting to use `use_query` to fetch non-ORM data.\n\n"
255255
"If these situations seem correct, you may want to consider disabling the postprocessor via `QueryOptions`."
256256
)
257+
258+
return data

0 commit comments

Comments
 (0)