reactpy_django 5.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. js/node_modules/@pyscript/core/src/stdlib/pyscript/__init__.py +61 -0
  2. js/node_modules/@pyscript/core/src/stdlib/pyscript/display.py +177 -0
  3. js/node_modules/@pyscript/core/src/stdlib/pyscript/event_handling.py +76 -0
  4. js/node_modules/@pyscript/core/src/stdlib/pyscript/fetch.py +87 -0
  5. js/node_modules/@pyscript/core/src/stdlib/pyscript/ffi.py +18 -0
  6. js/node_modules/@pyscript/core/src/stdlib/pyscript/flatted.py +148 -0
  7. js/node_modules/@pyscript/core/src/stdlib/pyscript/magic_js.py +79 -0
  8. js/node_modules/@pyscript/core/src/stdlib/pyscript/storage.py +60 -0
  9. js/node_modules/@pyscript/core/src/stdlib/pyscript/util.py +33 -0
  10. js/node_modules/@pyscript/core/src/stdlib/pyscript/web.py +1176 -0
  11. js/node_modules/@pyscript/core/src/stdlib/pyscript/websocket.py +71 -0
  12. js/node_modules/@pyscript/core/src/stdlib/pyscript/workers.py +43 -0
  13. js/node_modules/flatted/python/flatted.py +149 -0
  14. js/node_modules/flatted/python/test.py +63 -0
  15. js/node_modules/polyscript/python/mip.py +288 -0
  16. reactpy_django/__init__.py +32 -0
  17. reactpy_django/apps.py +11 -0
  18. reactpy_django/checks.py +558 -0
  19. reactpy_django/clean.py +141 -0
  20. reactpy_django/components.py +284 -0
  21. reactpy_django/config.py +128 -0
  22. reactpy_django/database.py +31 -0
  23. reactpy_django/decorators.py +65 -0
  24. reactpy_django/exceptions.py +34 -0
  25. reactpy_django/hooks.py +469 -0
  26. reactpy_django/html.py +3 -0
  27. reactpy_django/http/__init__.py +0 -0
  28. reactpy_django/http/urls.py +18 -0
  29. reactpy_django/http/views.py +62 -0
  30. reactpy_django/management/__init__.py +0 -0
  31. reactpy_django/management/commands/__init__.py +0 -0
  32. reactpy_django/management/commands/clean_reactpy.py +37 -0
  33. reactpy_django/migrations/0001_initial.py +25 -0
  34. reactpy_django/migrations/0002_rename_created_at_componentparams_last_accessed.py +17 -0
  35. reactpy_django/migrations/0003_componentsession_delete_componentparams.py +28 -0
  36. reactpy_django/migrations/0004_config.py +27 -0
  37. reactpy_django/migrations/0005_alter_componentsession_last_accessed.py +17 -0
  38. reactpy_django/migrations/0006_userdatamodel.py +28 -0
  39. reactpy_django/migrations/__init__.py +0 -0
  40. reactpy_django/models.py +48 -0
  41. reactpy_django/py.typed +1 -0
  42. reactpy_django/pyscript/__init__.py +0 -0
  43. reactpy_django/pyscript/component_template.py +26 -0
  44. reactpy_django/pyscript/layout_handler.py +139 -0
  45. reactpy_django/router/__init__.py +5 -0
  46. reactpy_django/router/converters.py +8 -0
  47. reactpy_django/router/resolvers.py +22 -0
  48. reactpy_django/static/reactpy_django/client.js +1 -0
  49. reactpy_django/static/reactpy_django/morphdom/morphdom-esm.js +769 -0
  50. reactpy_django/static/reactpy_django/morphdom/morphdom-factory.js +705 -0
  51. reactpy_django/static/reactpy_django/morphdom/morphdom-umd.js +777 -0
  52. reactpy_django/static/reactpy_django/morphdom/morphdom-umd.min.js +1 -0
  53. reactpy_django/static/reactpy_django/morphdom/morphdom.js +771 -0
  54. reactpy_django/static/reactpy_django/pyscript/codemirror-BEtcgaoQ.js +2 -0
  55. reactpy_django/static/reactpy_django/pyscript/codemirror-BEtcgaoQ.js.map +1 -0
  56. reactpy_django/static/reactpy_django/pyscript/codemirror_commands-DDxffOmd.js +2 -0
  57. reactpy_django/static/reactpy_django/pyscript/codemirror_commands-DDxffOmd.js.map +1 -0
  58. reactpy_django/static/reactpy_django/pyscript/codemirror_lang-python-CnWnFqxD.js +2 -0
  59. reactpy_django/static/reactpy_django/pyscript/codemirror_lang-python-CnWnFqxD.js.map +1 -0
  60. reactpy_django/static/reactpy_django/pyscript/codemirror_language-CjmvX4ix.js +2 -0
  61. reactpy_django/static/reactpy_django/pyscript/codemirror_language-CjmvX4ix.js.map +1 -0
  62. reactpy_django/static/reactpy_django/pyscript/codemirror_state-D1qTXrff.js +2 -0
  63. reactpy_django/static/reactpy_django/pyscript/codemirror_state-D1qTXrff.js.map +1 -0
  64. reactpy_django/static/reactpy_django/pyscript/codemirror_view-DVb8uYMr.js +2 -0
  65. reactpy_django/static/reactpy_django/pyscript/codemirror_view-DVb8uYMr.js.map +1 -0
  66. reactpy_django/static/reactpy_django/pyscript/core-CjO3FOKB.js +2 -0
  67. reactpy_django/static/reactpy_django/pyscript/core-CjO3FOKB.js.map +1 -0
  68. reactpy_django/static/reactpy_django/pyscript/core.css +1 -0
  69. reactpy_django/static/reactpy_django/pyscript/core.js +2 -0
  70. reactpy_django/static/reactpy_django/pyscript/core.js.map +1 -0
  71. reactpy_django/static/reactpy_django/pyscript/deprecations-manager-pFtn19mE.js +2 -0
  72. reactpy_django/static/reactpy_django/pyscript/deprecations-manager-pFtn19mE.js.map +1 -0
  73. reactpy_django/static/reactpy_django/pyscript/error-tq-z48YI.js +2 -0
  74. reactpy_django/static/reactpy_django/pyscript/error-tq-z48YI.js.map +1 -0
  75. reactpy_django/static/reactpy_django/pyscript/index-S1Do43bx.js +2 -0
  76. reactpy_django/static/reactpy_django/pyscript/index-S1Do43bx.js.map +1 -0
  77. reactpy_django/static/reactpy_django/pyscript/mpy-DovD7Qjy.js +2 -0
  78. reactpy_django/static/reactpy_django/pyscript/mpy-DovD7Qjy.js.map +1 -0
  79. reactpy_django/static/reactpy_django/pyscript/py-BUsUWVJg.js +2 -0
  80. reactpy_django/static/reactpy_django/pyscript/py-BUsUWVJg.js.map +1 -0
  81. reactpy_django/static/reactpy_django/pyscript/py-editor-CeySmmer.js +2 -0
  82. reactpy_django/static/reactpy_django/pyscript/py-editor-CeySmmer.js.map +1 -0
  83. reactpy_django/static/reactpy_django/pyscript/py-terminal-CH_wV7wQ.js +2 -0
  84. reactpy_django/static/reactpy_django/pyscript/py-terminal-CH_wV7wQ.js.map +1 -0
  85. reactpy_django/static/reactpy_django/pyscript/storage.js +2 -0
  86. reactpy_django/static/reactpy_django/pyscript/storage.js.map +1 -0
  87. reactpy_django/static/reactpy_django/pyscript/toml-CvAfdf9_.js +3 -0
  88. reactpy_django/static/reactpy_django/pyscript/toml-CvAfdf9_.js.map +1 -0
  89. reactpy_django/static/reactpy_django/pyscript/toml-DiUM0_qs.js +3 -0
  90. reactpy_django/static/reactpy_django/pyscript/toml-DiUM0_qs.js.map +1 -0
  91. reactpy_django/static/reactpy_django/pyscript/xterm-BY7uk_OU.js +2 -0
  92. reactpy_django/static/reactpy_django/pyscript/xterm-BY7uk_OU.js.map +1 -0
  93. reactpy_django/static/reactpy_django/pyscript/xterm-readline-CZfBw7ic.js +2 -0
  94. reactpy_django/static/reactpy_django/pyscript/xterm-readline-CZfBw7ic.js.map +1 -0
  95. reactpy_django/static/reactpy_django/pyscript/xterm.css +7 -0
  96. reactpy_django/static/reactpy_django/pyscript/xterm_addon-fit--gyF3PcZ.js +2 -0
  97. reactpy_django/static/reactpy_django/pyscript/xterm_addon-fit--gyF3PcZ.js.map +1 -0
  98. reactpy_django/static/reactpy_django/pyscript/xterm_addon-web-links-Cnej-nJ6.js +2 -0
  99. reactpy_django/static/reactpy_django/pyscript/xterm_addon-web-links-Cnej-nJ6.js.map +1 -0
  100. reactpy_django/static/reactpy_django/pyscript/zip-DrwYHuF9.js +2 -0
  101. reactpy_django/static/reactpy_django/pyscript/zip-DrwYHuF9.js.map +1 -0
  102. reactpy_django/static/reactpy_django/pyscript-custom.css +3 -0
  103. reactpy_django/static/reactpy_django/pyscript-hide-debug.css +3 -0
  104. reactpy_django/templates/reactpy/component.html +27 -0
  105. reactpy_django/templates/reactpy/pyscript_component.html +2 -0
  106. reactpy_django/templates/reactpy/pyscript_setup.html +8 -0
  107. reactpy_django/templatetags/__init__.py +0 -0
  108. reactpy_django/templatetags/reactpy.py +250 -0
  109. reactpy_django/types.py +81 -0
  110. reactpy_django/utils.py +560 -0
  111. reactpy_django/websocket/__init__.py +0 -0
  112. reactpy_django/websocket/consumer.py +227 -0
  113. reactpy_django/websocket/paths.py +15 -0
  114. reactpy_django-5.0.0.dist-info/LICENSE.md +9 -0
  115. reactpy_django-5.0.0.dist-info/METADATA +152 -0
  116. reactpy_django-5.0.0.dist-info/RECORD +118 -0
  117. reactpy_django-5.0.0.dist-info/WHEEL +5 -0
  118. reactpy_django-5.0.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,3 @@
1
+ py-script {
2
+ display: none;
3
+ }
@@ -0,0 +1,3 @@
1
+ .py-error {
2
+ display: none;
3
+ }
@@ -0,0 +1,27 @@
1
+ {% load static %}
2
+
3
+ {% if reactpy_failure and reactpy_debug_mode %}
4
+ <pre>{% firstof reactpy_error "UnknownError" %}: "{% firstof reactpy_dotted_path "UnknownPath" %}"</pre>
5
+ {% endif %}
6
+
7
+ {% if not reactpy_failure %}
8
+ {% if reactpy_class %}<div id="{{reactpy_uuid}}" class="{{reactpy_class}}"></div>{% endif %}
9
+ {% if not reactpy_class %}<div id="{{reactpy_uuid}}"></div>{% endif %}
10
+ {% if reactpy_prerender_html %}<div id="{{reactpy_uuid}}-prerender">{{reactpy_prerender_html|safe}}</div>{% endif %}
11
+ {% if reactpy_offline_html %}<div id="{{reactpy_uuid}}-offline" hidden>{{reactpy_offline_html|safe}}</div>{% endif %}
12
+ <script type="module" crossorigin="anonymous">
13
+ import { mountComponent } from "{% static 'reactpy_django/client.js' %}";
14
+ const mountElement = document.getElementById("{{reactpy_uuid}}");
15
+ mountComponent(
16
+ mountElement,
17
+ "{{reactpy_host}}",
18
+ "{{reactpy_url_prefix}}",
19
+ "{{reactpy_component_path}}",
20
+ "{{reactpy_resolved_web_modules_path}}",
21
+ Number("{{reactpy_reconnect_interval}}"),
22
+ Number("{{reactpy_reconnect_max_interval}}"),
23
+ Number("{{reactpy_reconnect_max_retries}}"),
24
+ Number("{{reactpy_reconnect_backoff_multiplier}}"),
25
+ );
26
+ </script>
27
+ {% endif %}
@@ -0,0 +1,2 @@
1
+ <div id="pyscript-{{pyscript_uuid}}" class="pyscript" data-uuid="{{pyscript_uuid}}">{{pyscript_initial_html}}</div>
2
+ <py-script async>{{pyscript_executor}}</py-script>
@@ -0,0 +1,8 @@
1
+ {% load static %}
2
+ <link rel="stylesheet" href="{% static 'reactpy_django/pyscript/core.css' %}" />
3
+ <link rel="stylesheet" href="{% static 'reactpy_django/pyscript-custom.css' %}" />
4
+ {% if not reactpy_debug_mode %}
5
+ <link rel="stylesheet" href="{% static 'reactpy_django/pyscript-hide-debug.css' %}" />
6
+ {% endif %}
7
+ <script type="module" async crossorigin="anonymous" src="{% static 'reactpy_django/pyscript/core.js' %}"></script>
8
+ <py-script async config='{{pyscript_config}}'>{{pyscript_layout_handler}}</py-script>
File without changes
@@ -0,0 +1,250 @@
1
+ from __future__ import annotations
2
+
3
+ from logging import getLogger
4
+ from uuid import uuid4
5
+
6
+ from django import template
7
+ from django.http import HttpRequest
8
+ from django.urls import NoReverseMatch, reverse
9
+ from reactpy.core.types import ComponentConstructor, ComponentType, VdomDict
10
+
11
+ from reactpy_django import config as reactpy_config
12
+ from reactpy_django.exceptions import (
13
+ ComponentCarrierError,
14
+ ComponentDoesNotExistError,
15
+ ComponentParamError,
16
+ InvalidHostError,
17
+ OfflineComponentMissing,
18
+ )
19
+ from reactpy_django.utils import (
20
+ PYSCRIPT_LAYOUT_HANDLER,
21
+ extend_pyscript_config,
22
+ prerender_component,
23
+ render_pyscript_template,
24
+ save_component_params,
25
+ strtobool,
26
+ validate_component_args,
27
+ validate_host,
28
+ vdom_or_component_to_string,
29
+ )
30
+
31
+ try:
32
+ RESOLVED_WEB_MODULES_PATH = reverse("reactpy:web_modules", args=["/"]).strip("/")
33
+ except NoReverseMatch:
34
+ RESOLVED_WEB_MODULES_PATH = ""
35
+ register = template.Library()
36
+ _logger = getLogger(__name__)
37
+
38
+
39
+ @register.inclusion_tag("reactpy/component.html", takes_context=True)
40
+ def component(
41
+ context: template.RequestContext,
42
+ dotted_path: str,
43
+ *args,
44
+ host: str | None = None,
45
+ prerender: str = str(reactpy_config.REACTPY_PRERENDER),
46
+ offline: str = "",
47
+ **kwargs,
48
+ ):
49
+ """This tag is used to embed an existing ReactPy component into your HTML template.
50
+
51
+ Args:
52
+ dotted_path: The dotted path to the component to render.
53
+ *args: The positional arguments to provide to the component.
54
+
55
+ Keyword Args:
56
+ class: The HTML class to apply to the top-level component div.
57
+ key: Force the component's root node to use a specific key value. Using \
58
+ key within a template tag is effectively useless.
59
+ host: The host to use for ReactPy connections. If set to `None`, \
60
+ the host will be automatically configured. \
61
+ Example values include: `localhost:8000`, `example.com`, `example.com/subdir`
62
+ prerender: Configures whether to pre-render this component, which \
63
+ enables SEO compatibility and reduces perceived latency.
64
+ offline: The dotted path to the component to render when the client is offline.
65
+ **kwargs: The keyword arguments to provide to the component.
66
+
67
+ Example ::
68
+
69
+ {% load reactpy %}
70
+ <!DOCTYPE html>
71
+ <html>
72
+ <body>
73
+ {% component "example_project.my_app.components.hello_world" recipient="World" %}
74
+ </body>
75
+ </html>
76
+ """
77
+ request: HttpRequest | None = context.get("request")
78
+ perceived_host = (request.get_host() if request else "").strip("/")
79
+ host = (
80
+ host
81
+ or (
82
+ next(reactpy_config.REACTPY_DEFAULT_HOSTS)
83
+ if reactpy_config.REACTPY_DEFAULT_HOSTS
84
+ else ""
85
+ )
86
+ ).strip("/")
87
+ is_local = not host or host.startswith(perceived_host)
88
+ uuid = str(uuid4())
89
+ class_ = kwargs.pop("class", "")
90
+ has_args = bool(args or kwargs)
91
+ user_component: ComponentConstructor | None = None
92
+ _prerender_html = ""
93
+ _offline_html = ""
94
+
95
+ # Validate the host
96
+ if host and reactpy_config.REACTPY_DEBUG_MODE:
97
+ try:
98
+ validate_host(host)
99
+ except InvalidHostError as e:
100
+ return failure_context(dotted_path, e)
101
+
102
+ # Fetch the component
103
+ if is_local:
104
+ user_component = reactpy_config.REACTPY_REGISTERED_COMPONENTS.get(dotted_path)
105
+ if not user_component:
106
+ msg = f"Component '{dotted_path}' is not registered as a root component. "
107
+ _logger.error(msg)
108
+ return failure_context(dotted_path, ComponentDoesNotExistError(msg))
109
+
110
+ # Validate the component args & kwargs
111
+ if is_local and reactpy_config.REACTPY_DEBUG_MODE:
112
+ try:
113
+ validate_component_args(user_component, *args, **kwargs)
114
+ except ComponentParamError as e:
115
+ _logger.error(str(e))
116
+ return failure_context(dotted_path, e)
117
+
118
+ # Store args & kwargs in the database (fetched by our websocket later)
119
+ if has_args:
120
+ try:
121
+ save_component_params(args, kwargs, uuid)
122
+ except Exception as e:
123
+ _logger.exception(
124
+ "An unknown error has occurred while saving component params for '%s'.",
125
+ dotted_path,
126
+ )
127
+ return failure_context(dotted_path, e)
128
+
129
+ # Pre-render the component, if requested
130
+ if strtobool(prerender):
131
+ if not is_local:
132
+ msg = "Cannot pre-render non-local components."
133
+ _logger.error(msg)
134
+ return failure_context(dotted_path, ComponentDoesNotExistError(msg))
135
+ if not user_component:
136
+ msg = "Cannot pre-render component that is not registered."
137
+ _logger.error(msg)
138
+ return failure_context(dotted_path, ComponentDoesNotExistError(msg))
139
+ if not request:
140
+ msg = (
141
+ "Cannot pre-render component without a HTTP request. Are you missing the "
142
+ "request context processor in settings.py:TEMPLATES['OPTIONS']['context_processors']?"
143
+ )
144
+ _logger.error(msg)
145
+ return failure_context(dotted_path, ComponentCarrierError(msg))
146
+ _prerender_html = prerender_component(
147
+ user_component, args, kwargs, uuid, request
148
+ )
149
+
150
+ # Fetch the offline component's HTML, if requested
151
+ if offline:
152
+ offline_component = reactpy_config.REACTPY_REGISTERED_COMPONENTS.get(offline)
153
+ if not offline_component:
154
+ msg = f"Cannot render offline component '{offline}'. It is not registered as a component."
155
+ _logger.error(msg)
156
+ return failure_context(dotted_path, OfflineComponentMissing(msg))
157
+ if not request:
158
+ msg = (
159
+ "Cannot render an offline component without a HTTP request. Are you missing the "
160
+ "request context processor in settings.py:TEMPLATES['OPTIONS']['context_processors']?"
161
+ )
162
+ _logger.error(msg)
163
+ return failure_context(dotted_path, ComponentCarrierError(msg))
164
+ _offline_html = prerender_component(offline_component, [], {}, uuid, request)
165
+
166
+ # Return the template rendering context
167
+ return {
168
+ "reactpy_class": class_,
169
+ "reactpy_uuid": uuid,
170
+ "reactpy_host": host or perceived_host,
171
+ "reactpy_url_prefix": reactpy_config.REACTPY_URL_PREFIX,
172
+ "reactpy_component_path": f"{dotted_path}/{uuid}/{int(has_args)}/",
173
+ "reactpy_resolved_web_modules_path": RESOLVED_WEB_MODULES_PATH,
174
+ "reactpy_reconnect_interval": reactpy_config.REACTPY_RECONNECT_INTERVAL,
175
+ "reactpy_reconnect_max_interval": reactpy_config.REACTPY_RECONNECT_MAX_INTERVAL,
176
+ "reactpy_reconnect_backoff_multiplier": reactpy_config.REACTPY_RECONNECT_BACKOFF_MULTIPLIER,
177
+ "reactpy_reconnect_max_retries": reactpy_config.REACTPY_RECONNECT_MAX_RETRIES,
178
+ "reactpy_prerender_html": _prerender_html,
179
+ "reactpy_offline_html": _offline_html,
180
+ }
181
+
182
+
183
+ @register.inclusion_tag("reactpy/pyscript_component.html", takes_context=True)
184
+ def pyscript_component(
185
+ context: template.RequestContext,
186
+ *file_paths: str,
187
+ initial: str | VdomDict | ComponentType = "",
188
+ root: str = "root",
189
+ ):
190
+ """
191
+ Args:
192
+ file_paths: File path to your client-side component. If multiple paths are \
193
+ provided, the contents are automatically merged.
194
+
195
+ Kwargs:
196
+ initial: The initial HTML that is displayed prior to the PyScript component \
197
+ loads. This can either be a string containing raw HTML, a \
198
+ `#!python reactpy.html` snippet, or a non-interactive component.
199
+ root: The name of the root component function.
200
+ """
201
+ if not file_paths:
202
+ raise ValueError(
203
+ "At least one file path must be provided to the 'pyscript_component' tag."
204
+ )
205
+
206
+ uuid = uuid4().hex
207
+ request: HttpRequest | None = context.get("request")
208
+ initial = vdom_or_component_to_string(initial, request=request, uuid=uuid)
209
+ executor = render_pyscript_template(file_paths, uuid, root)
210
+
211
+ return {
212
+ "pyscript_executor": executor,
213
+ "pyscript_uuid": uuid,
214
+ "pyscript_initial_html": initial,
215
+ }
216
+
217
+
218
+ @register.inclusion_tag("reactpy/pyscript_setup.html")
219
+ def pyscript_setup(
220
+ *extra_py: str,
221
+ extra_js: str | dict = "",
222
+ config: str | dict = "",
223
+ ):
224
+ """
225
+ Args:
226
+ extra_py: Dependencies that need to be loaded on the page for \
227
+ your PyScript components. Each dependency must be contained \
228
+ within it's own string and written in Python requirements file syntax.
229
+
230
+ Kwargs:
231
+ extra_js: A JSON string or Python dictionary containing a vanilla \
232
+ JavaScript module URL and the `name: str` to access it within \
233
+ `pyscript.js_modules.*`.
234
+ config: A JSON string or Python dictionary containing PyScript \
235
+ configuration values.
236
+ """
237
+ return {
238
+ "pyscript_config": extend_pyscript_config(extra_py, extra_js, config),
239
+ "pyscript_layout_handler": PYSCRIPT_LAYOUT_HANDLER,
240
+ "reactpy_debug_mode": reactpy_config.REACTPY_DEBUG_MODE,
241
+ }
242
+
243
+
244
+ def failure_context(dotted_path: str, error: Exception):
245
+ return {
246
+ "reactpy_failure": True,
247
+ "reactpy_debug_mode": reactpy_config.REACTPY_DEBUG_MODE,
248
+ "reactpy_dotted_path": dotted_path,
249
+ "reactpy_error": type(error).__name__,
250
+ }
@@ -0,0 +1,81 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import (
5
+ TYPE_CHECKING,
6
+ Any,
7
+ Callable,
8
+ Generic,
9
+ MutableMapping,
10
+ NamedTuple,
11
+ Protocol,
12
+ Sequence,
13
+ TypeVar,
14
+ Union,
15
+ )
16
+
17
+ from django.http import HttpRequest
18
+ from reactpy.types import Connection
19
+ from typing_extensions import ParamSpec
20
+
21
+ if TYPE_CHECKING:
22
+ from reactpy_django.websocket.consumer import ReactpyAsyncWebsocketConsumer
23
+
24
+
25
+ FuncParams = ParamSpec("FuncParams")
26
+ Inferred = TypeVar("Inferred")
27
+ ConnectionType = Connection[Union["ReactpyAsyncWebsocketConsumer", HttpRequest]]
28
+
29
+
30
+ @dataclass
31
+ class Query(Generic[Inferred]):
32
+ """Queries generated by the `use_query` hook."""
33
+
34
+ data: Inferred
35
+ loading: bool
36
+ error: Exception | None
37
+ refetch: Callable[[], None]
38
+
39
+
40
+ @dataclass
41
+ class Mutation(Generic[FuncParams]):
42
+ """Mutations generated by the `use_mutation` hook."""
43
+
44
+ execute: Callable[FuncParams, None]
45
+ loading: bool
46
+ error: Exception | None
47
+ reset: Callable[[], None]
48
+
49
+ def __call__(self, *args: FuncParams.args, **kwargs: FuncParams.kwargs) -> None:
50
+ """Execute the mutation."""
51
+ self.execute(*args, **kwargs)
52
+
53
+
54
+ class AsyncPostprocessor(Protocol):
55
+ async def __call__(self, data: Any) -> Any: ...
56
+
57
+
58
+ class SyncPostprocessor(Protocol):
59
+ def __call__(self, data: Any) -> Any: ...
60
+
61
+
62
+ @dataclass
63
+ class ComponentParams:
64
+ """Container used for serializing component parameters.
65
+ This dataclass is pickled & stored in the database, then unpickled when needed."""
66
+
67
+ args: Sequence
68
+ kwargs: MutableMapping[str, Any]
69
+
70
+
71
+ class UserData(NamedTuple):
72
+ query: Query[dict | None]
73
+ mutation: Mutation[dict]
74
+
75
+
76
+ class AsyncMessageReceiver(Protocol):
77
+ async def __call__(self, message: dict) -> None: ...
78
+
79
+
80
+ class AsyncMessageSender(Protocol):
81
+ async def __call__(self, message: dict) -> None: ...