pulse-framework 0.1.55__py3-none-any.whl → 0.1.56__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 (70) hide show
  1. pulse/__init__.py +5 -6
  2. pulse/app.py +144 -57
  3. pulse/channel.py +139 -7
  4. pulse/cli/cmd.py +16 -2
  5. pulse/codegen/codegen.py +43 -12
  6. pulse/component.py +104 -0
  7. pulse/components/for_.py +30 -4
  8. pulse/components/if_.py +28 -5
  9. pulse/components/react_router.py +61 -3
  10. pulse/context.py +39 -5
  11. pulse/cookies.py +108 -4
  12. pulse/decorators.py +193 -24
  13. pulse/env.py +56 -2
  14. pulse/form.py +198 -5
  15. pulse/helpers.py +7 -1
  16. pulse/hooks/core.py +135 -5
  17. pulse/hooks/effects.py +61 -77
  18. pulse/hooks/init.py +60 -1
  19. pulse/hooks/runtime.py +241 -0
  20. pulse/hooks/setup.py +77 -0
  21. pulse/hooks/stable.py +58 -1
  22. pulse/hooks/state.py +107 -20
  23. pulse/js/__init__.py +40 -24
  24. pulse/js/array.py +9 -6
  25. pulse/js/console.py +15 -12
  26. pulse/js/date.py +9 -6
  27. pulse/js/document.py +5 -2
  28. pulse/js/error.py +7 -4
  29. pulse/js/json.py +9 -6
  30. pulse/js/map.py +8 -5
  31. pulse/js/math.py +9 -6
  32. pulse/js/navigator.py +5 -2
  33. pulse/js/number.py +9 -6
  34. pulse/js/obj.py +16 -13
  35. pulse/js/object.py +9 -6
  36. pulse/js/promise.py +19 -13
  37. pulse/js/pulse.py +28 -25
  38. pulse/js/react.py +94 -55
  39. pulse/js/regexp.py +7 -4
  40. pulse/js/set.py +8 -5
  41. pulse/js/string.py +9 -6
  42. pulse/js/weakmap.py +8 -5
  43. pulse/js/weakset.py +8 -5
  44. pulse/js/window.py +6 -3
  45. pulse/messages.py +5 -0
  46. pulse/middleware.py +147 -76
  47. pulse/plugin.py +76 -5
  48. pulse/queries/client.py +186 -39
  49. pulse/queries/common.py +52 -3
  50. pulse/queries/infinite_query.py +154 -2
  51. pulse/queries/mutation.py +127 -7
  52. pulse/queries/query.py +112 -11
  53. pulse/react_component.py +66 -3
  54. pulse/reactive.py +314 -30
  55. pulse/reactive_extensions.py +106 -26
  56. pulse/render_session.py +304 -173
  57. pulse/request.py +46 -11
  58. pulse/routing.py +140 -4
  59. pulse/serializer.py +71 -0
  60. pulse/state.py +177 -9
  61. pulse/test_helpers.py +15 -0
  62. pulse/transpiler/__init__.py +0 -3
  63. pulse/transpiler/py_module.py +1 -7
  64. pulse/user_session.py +119 -18
  65. {pulse_framework-0.1.55.dist-info → pulse_framework-0.1.56.dist-info}/METADATA +5 -5
  66. pulse_framework-0.1.56.dist-info/RECORD +127 -0
  67. pulse/transpiler/react_component.py +0 -44
  68. pulse_framework-0.1.55.dist-info/RECORD +0 -127
  69. {pulse_framework-0.1.55.dist-info → pulse_framework-0.1.56.dist-info}/WHEEL +0 -0
  70. {pulse_framework-0.1.55.dist-info → pulse_framework-0.1.56.dist-info}/entry_points.txt +0 -0
pulse/js/react.py CHANGED
@@ -2,14 +2,17 @@
2
2
  JavaScript React module.
3
3
 
4
4
  Usage:
5
- from pulse.js.react import useState, useEffect, useRef
6
- state, setState = useState(0) # -> const [state, setState] = useState(0)
7
- useEffect(lambda: print("hi"), []) # -> useEffect(() => console.log("hi"), [])
8
- ref = useRef(None) # -> const ref = useRef(null)
9
-
10
- # Also available as namespace:
11
- import pulse.js.react as React
12
- React.useState(0) # -> React.useState(0)
5
+
6
+ ```python
7
+ from pulse.js.react import useState, useEffect, useRef
8
+ state, setState = useState(0) # -> const [state, setState] = useState(0)
9
+ useEffect(lambda: print("hi"), []) # -> useEffect(() => console.log("hi"), [])
10
+ ref = useRef(None) # -> const ref = useRef(null)
11
+
12
+ # Also available as namespace:
13
+ import pulse.js.react as React
14
+ React.useState(0) # -> React.useState(0)
15
+ ```
13
16
  """
14
17
 
15
18
  import ast as _ast
@@ -116,9 +119,12 @@ def useState(
116
119
  """Returns a stateful value and a function to update it.
117
120
 
118
121
  Example:
119
- count, set_count = useState(0)
120
- set_count(count + 1)
121
- set_count(lambda prev: prev + 1)
122
+
123
+ ```python
124
+ count, set_count = useState(0)
125
+ set_count(count + 1)
126
+ set_count(lambda prev: prev + 1)
127
+ ```
122
128
  """
123
129
  ...
124
130
 
@@ -128,16 +134,19 @@ def useReducer(
128
134
  initial_arg: S,
129
135
  init: _Callable[[S], S] | None = None,
130
136
  ) -> tuple[S, Dispatch[A]]:
131
- """An alternative to useState for complex state logic.
137
+ """An alternative to `useState` for complex state logic.
132
138
 
133
139
  Example:
134
- def reducer(state, action):
135
- if action['type'] == 'increment':
136
- return {'count': state['count'] + 1}
137
- return state
138
140
 
139
- state, dispatch = useReducer(reducer, {'count': 0})
140
- dispatch({'type': 'increment'})
141
+ ```python
142
+ def reducer(state, action):
143
+ if action['type'] == 'increment':
144
+ return {'count': state['count'] + 1}
145
+ return state
146
+
147
+ state, dispatch = useReducer(reducer, {'count': 0})
148
+ dispatch({'type': 'increment'})
149
+ ```
141
150
  """
142
151
  ...
143
152
 
@@ -154,8 +163,11 @@ def useEffect(
154
163
  """Accepts a function that contains imperative, possibly effectful code.
155
164
 
156
165
  Example:
157
- useEffect(lambda: print("mounted"), [])
158
- useEffect(lambda: (print("update"), lambda: print("cleanup"))[-1], [dep])
166
+
167
+ ```python
168
+ useEffect(lambda: print("mounted"), [])
169
+ useEffect(lambda: (print("update"), lambda: print("cleanup"))[-1], [dep])
170
+ ```
159
171
  """
160
172
  ...
161
173
 
@@ -164,10 +176,13 @@ def useLayoutEffect(
164
176
  effect: _Callable[[], None | _Callable[[], None]],
165
177
  deps: list[_Any] | None = None,
166
178
  ) -> None:
167
- """Like useEffect, but fires synchronously after all DOM mutations.
179
+ """Like `useEffect`, but fires synchronously after all DOM mutations.
168
180
 
169
181
  Example:
170
- useLayoutEffect(lambda: measure_element(), [])
182
+
183
+ ```python
184
+ useLayoutEffect(lambda: measure_element(), [])
185
+ ```
171
186
  """
172
187
  ...
173
188
 
@@ -191,9 +206,12 @@ def useRef(initial_value: T) -> MutableRefObject[T]:
191
206
  """Returns a mutable ref object.
192
207
 
193
208
  Example:
194
- input_ref = useRef(None)
195
- # In JSX: <input ref={input_ref} />
196
- input_ref.current.focus()
209
+
210
+ ```python
211
+ input_ref = useRef(None)
212
+ # In JSX: <input ref={input_ref} />
213
+ input_ref.current.focus()
214
+ ```
197
215
  """
198
216
  ...
199
217
 
@@ -216,7 +234,10 @@ def useMemo(factory: _Callable[[], T], deps: list[_Any]) -> T:
216
234
  """Returns a memoized value.
217
235
 
218
236
  Example:
219
- expensive = useMemo(lambda: compute_expensive(a, b), [a, b])
237
+
238
+ ```python
239
+ expensive = useMemo(lambda: compute_expensive(a, b), [a, b])
240
+ ```
220
241
  """
221
242
  ...
222
243
 
@@ -225,7 +246,10 @@ def useCallback(callback: T, deps: list[_Any]) -> T:
225
246
  """Returns a memoized callback.
226
247
 
227
248
  Example:
228
- handle_click = useCallback(lambda e: print(e), [])
249
+
250
+ ```python
251
+ handle_click = useCallback(lambda e: print(e), [])
252
+ ```
229
253
  """
230
254
  ...
231
255
 
@@ -239,8 +263,11 @@ def useTransition() -> tuple[bool, TransitionStartFunction]:
239
263
  """Returns a stateful value for pending state and a function to start transition.
240
264
 
241
265
  Example:
242
- is_pending, start_transition = useTransition()
243
- start_transition(lambda: set_state(new_value))
266
+
267
+ ```python
268
+ is_pending, start_transition = useTransition()
269
+ start_transition(lambda: set_state(new_value))
270
+ ```
244
271
  """
245
272
  ...
246
273
 
@@ -254,7 +281,10 @@ def useContext(context: Context[T]) -> T:
254
281
  """Returns the current context value for the given context.
255
282
 
256
283
  Example:
257
- theme = useContext(ThemeContext)
284
+
285
+ ```python
286
+ theme = useContext(ThemeContext)
287
+ ```
258
288
  """
259
289
  ...
260
290
 
@@ -268,9 +298,12 @@ def useId() -> str:
268
298
  """Generates a unique ID that is stable across server and client.
269
299
 
270
300
  Example:
271
- id = useId()
272
- # <label htmlFor={id}>Name</label>
273
- # <input id={id} />
301
+
302
+ ```python
303
+ id = useId()
304
+ # <label htmlFor={id}>Name</label>
305
+ # <input id={id} />
306
+ ```
274
307
  """
275
308
  ...
276
309
 
@@ -288,10 +321,13 @@ def useSyncExternalStore(
288
321
  """Subscribe to an external store.
289
322
 
290
323
  Example:
291
- width = useSyncExternalStore(
292
- subscribe_to_resize,
293
- lambda: window.innerWidth
294
- )
324
+
325
+ ```python
326
+ width = useSyncExternalStore(
327
+ subscribe_to_resize,
328
+ lambda: window.innerWidth
329
+ )
330
+ ```
295
331
  """
296
332
  ...
297
333
 
@@ -337,27 +373,30 @@ def forwardRef(
337
373
 
338
374
 
339
375
  class _LazyComponentFactory(_Expr):
340
- """React.lazy binding that works both at definition time and in @javascript.
376
+ """React.lazy binding that works both at definition time and in `@javascript`.
341
377
 
342
- This Expr represents React's lazy function. It can be:
343
- - Called at Python definition time: lazy(factory) → Jsx(Constant(...))
344
- - Used as a reference in @javascript: some_fn(lazy) → some_fn(lazy)
345
- - Called inside @javascript: lazy(factory) → creates Constant+Jsx
378
+ This Expr represents React's `lazy` function. It can be:
379
+ - Called at Python definition time: `lazy(factory)``Jsx(Constant(...))`
380
+ - Used as a reference in `@javascript`: `some_fn(lazy)``some_fn(lazy)`
381
+ - Called inside `@javascript`: `lazy(factory)` → creates `Constant+Jsx`
346
382
 
347
383
  Usage:
348
- # At definition time (Python executes this)
349
- LazyChart = lazy(Import("Chart", "./Chart", lazy=True))
350
-
351
- # As reference in transpiled code
352
- @javascript
353
- def foo():
354
- return higher_order_fn(lazy) # → higher_order_fn(lazy)
355
-
356
- # Called in transpiled code
357
- @javascript
358
- def bar():
359
- LazyComp = lazy(factory) # → const LazyComp_1 = lazy(factory)
360
- return LazyComp()
384
+
385
+ ```python
386
+ # At definition time (Python executes this)
387
+ LazyChart = lazy(Import("Chart", "./Chart", lazy=True))
388
+
389
+ # As reference in transpiled code
390
+ @javascript
391
+ def foo():
392
+ return higher_order_fn(lazy) # higher_order_fn(lazy)
393
+
394
+ # Called in transpiled code
395
+ @javascript
396
+ def bar():
397
+ LazyComp = lazy(factory) # → const LazyComp_1 = lazy(factory)
398
+ return LazyComp()
399
+ ```
361
400
  """
362
401
 
363
402
  __slots__: tuple[str, ...] = ("_lazy_import",)
pulse/js/regexp.py CHANGED
@@ -2,11 +2,14 @@
2
2
  JavaScript RegExp builtin module.
3
3
 
4
4
  Usage:
5
- from pulse.js import RegExp
6
- RegExp(pattern, flags) # -> new RegExp(pattern, flags)
7
5
 
8
- # Or import from module directly:
9
- from pulse.js.regexp import RegExp
6
+ ```python
7
+ from pulse.js import RegExp
8
+ RegExp(pattern, flags) # -> new RegExp(pattern, flags)
9
+
10
+ # Or import from module directly:
11
+ from pulse.js.regexp import RegExp
12
+ ```
10
13
  """
11
14
 
12
15
  from pulse.transpiler.js_module import JsModule
pulse/js/set.py CHANGED
@@ -2,12 +2,15 @@
2
2
  JavaScript Set builtin module.
3
3
 
4
4
  Usage:
5
- from pulse.js import Set
6
- Set() # -> new Set()
7
- Set([1, 2, 3]) # -> new Set([1, 2, 3])
8
5
 
9
- # Or import from module directly:
10
- from pulse.js.set import Set
6
+ ```python
7
+ from pulse.js import Set
8
+ Set() # -> new Set()
9
+ Set([1, 2, 3]) # -> new Set([1, 2, 3])
10
+
11
+ # Or import from module directly:
12
+ from pulse.js.set import Set
13
+ ```
11
14
  """
12
15
 
13
16
  from collections.abc import Callable as _Callable
pulse/js/string.py CHANGED
@@ -2,13 +2,16 @@
2
2
  JavaScript String builtin module.
3
3
 
4
4
  Usage:
5
- from pulse.js import String
6
- String(x) # -> new String(x)
7
- String.fromCharCode(65) # -> String.fromCharCode(65)
8
- String.fromCodePoint(0x1F600) # -> String.fromCodePoint(0x1F600)
9
5
 
10
- # Or import from module directly:
11
- from pulse.js.string import String
6
+ ```python
7
+ from pulse.js import String
8
+ String(x) # -> new String(x)
9
+ String.fromCharCode(65) # -> String.fromCharCode(65)
10
+ String.fromCodePoint(0x1F600) # -> String.fromCodePoint(0x1F600)
11
+
12
+ # Or import from module directly:
13
+ from pulse.js.string import String
14
+ ```
12
15
  """
13
16
 
14
17
  from typing import Any as _Any
pulse/js/weakmap.py CHANGED
@@ -2,12 +2,15 @@
2
2
  JavaScript WeakMap builtin module.
3
3
 
4
4
  Usage:
5
- from pulse.js import WeakMap
6
- WeakMap() # -> new WeakMap()
7
- WeakMap([[obj, "value"]]) # -> new WeakMap([[obj, "value"]])
8
5
 
9
- # Or import from module directly:
10
- from pulse.js.weakmap import WeakMap
6
+ ```python
7
+ from pulse.js import WeakMap
8
+ WeakMap() # -> new WeakMap()
9
+ WeakMap([[obj, "value"]]) # -> new WeakMap([[obj, "value"]])
10
+
11
+ # Or import from module directly:
12
+ from pulse.js.weakmap import WeakMap
13
+ ```
11
14
  """
12
15
 
13
16
  from collections.abc import Iterable as _Iterable
pulse/js/weakset.py CHANGED
@@ -2,12 +2,15 @@
2
2
  JavaScript WeakSet builtin module.
3
3
 
4
4
  Usage:
5
- from pulse.js import WeakSet
6
- WeakSet() # -> new WeakSet()
7
- WeakSet([obj1, obj2]) # -> new WeakSet([obj1, obj2])
8
5
 
9
- # Or import from module directly:
10
- from pulse.js.weakset import WeakSet
6
+ ```python
7
+ from pulse.js import WeakSet
8
+ WeakSet() # -> new WeakSet()
9
+ WeakSet([obj1, obj2]) # -> new WeakSet([obj1, obj2])
10
+
11
+ # Or import from module directly:
12
+ from pulse.js.weakset import WeakSet
13
+ ```
11
14
  """
12
15
 
13
16
  from collections.abc import Iterable as _Iterable
pulse/js/window.py CHANGED
@@ -1,9 +1,12 @@
1
1
  """Browser window global object.
2
2
 
3
3
  Usage:
4
- from pulse.js import window
5
- window.alert("Hello!") # -> window.alert("Hello!")
6
- window.innerWidth # -> window.innerWidth
4
+
5
+ ```python
6
+ from pulse.js import window
7
+ window.alert("Hello!") # -> window.alert("Hello!")
8
+ window.innerWidth # -> window.innerWidth
9
+ ```
7
10
  """
8
11
 
9
12
  from collections.abc import Callable as _Callable
pulse/messages.py CHANGED
@@ -48,6 +48,10 @@ class ServerNavigateToMessage(TypedDict):
48
48
  hard: bool
49
49
 
50
50
 
51
+ class ServerReloadMessage(TypedDict):
52
+ type: Literal["reload"]
53
+
54
+
51
55
  class ServerApiCallMessage(TypedDict):
52
56
  type: Literal["api_call"]
53
57
  # Correlation id to match request/response
@@ -158,6 +162,7 @@ ServerMessage = (
158
162
  | ServerErrorMessage
159
163
  | ServerApiCallMessage
160
164
  | ServerNavigateToMessage
165
+ | ServerReloadMessage
161
166
  | ServerChannelMessage
162
167
  | ServerJsExecMessage
163
168
  )