pulse-framework 0.1.62__tar.gz
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.
- pulse_framework-0.1.62/PKG-INFO +198 -0
- pulse_framework-0.1.62/README.md +178 -0
- pulse_framework-0.1.62/pyproject.toml +37 -0
- pulse_framework-0.1.62/src/pulse/__init__.py +1493 -0
- pulse_framework-0.1.62/src/pulse/_examples.py +29 -0
- pulse_framework-0.1.62/src/pulse/app.py +1086 -0
- pulse_framework-0.1.62/src/pulse/channel.py +607 -0
- pulse_framework-0.1.62/src/pulse/cli/__init__.py +0 -0
- pulse_framework-0.1.62/src/pulse/cli/cmd.py +575 -0
- pulse_framework-0.1.62/src/pulse/cli/dependencies.py +181 -0
- pulse_framework-0.1.62/src/pulse/cli/folder_lock.py +134 -0
- pulse_framework-0.1.62/src/pulse/cli/helpers.py +271 -0
- pulse_framework-0.1.62/src/pulse/cli/logging.py +102 -0
- pulse_framework-0.1.62/src/pulse/cli/models.py +35 -0
- pulse_framework-0.1.62/src/pulse/cli/packages.py +262 -0
- pulse_framework-0.1.62/src/pulse/cli/processes.py +292 -0
- pulse_framework-0.1.62/src/pulse/cli/secrets.py +39 -0
- pulse_framework-0.1.62/src/pulse/cli/uvicorn_log_config.py +87 -0
- pulse_framework-0.1.62/src/pulse/code_analysis.py +38 -0
- pulse_framework-0.1.62/src/pulse/codegen/__init__.py +0 -0
- pulse_framework-0.1.62/src/pulse/codegen/codegen.py +359 -0
- pulse_framework-0.1.62/src/pulse/codegen/templates/__init__.py +0 -0
- pulse_framework-0.1.62/src/pulse/codegen/templates/layout.py +106 -0
- pulse_framework-0.1.62/src/pulse/codegen/templates/route.py +345 -0
- pulse_framework-0.1.62/src/pulse/codegen/templates/routes_ts.py +42 -0
- pulse_framework-0.1.62/src/pulse/codegen/utils.py +20 -0
- pulse_framework-0.1.62/src/pulse/component.py +237 -0
- pulse_framework-0.1.62/src/pulse/components/__init__.py +0 -0
- pulse_framework-0.1.62/src/pulse/components/for_.py +83 -0
- pulse_framework-0.1.62/src/pulse/components/if_.py +86 -0
- pulse_framework-0.1.62/src/pulse/components/react_router.py +94 -0
- pulse_framework-0.1.62/src/pulse/context.py +108 -0
- pulse_framework-0.1.62/src/pulse/cookies.py +322 -0
- pulse_framework-0.1.62/src/pulse/decorators.py +344 -0
- pulse_framework-0.1.62/src/pulse/dom/__init__.py +0 -0
- pulse_framework-0.1.62/src/pulse/dom/elements.py +1024 -0
- pulse_framework-0.1.62/src/pulse/dom/events.py +445 -0
- pulse_framework-0.1.62/src/pulse/dom/props.py +1250 -0
- pulse_framework-0.1.62/src/pulse/dom/svg.py +0 -0
- pulse_framework-0.1.62/src/pulse/dom/tags.py +328 -0
- pulse_framework-0.1.62/src/pulse/dom/tags.pyi +480 -0
- pulse_framework-0.1.62/src/pulse/env.py +178 -0
- pulse_framework-0.1.62/src/pulse/form.py +538 -0
- pulse_framework-0.1.62/src/pulse/helpers.py +541 -0
- pulse_framework-0.1.62/src/pulse/hooks/__init__.py +0 -0
- pulse_framework-0.1.62/src/pulse/hooks/core.py +452 -0
- pulse_framework-0.1.62/src/pulse/hooks/effects.py +88 -0
- pulse_framework-0.1.62/src/pulse/hooks/init.py +668 -0
- pulse_framework-0.1.62/src/pulse/hooks/runtime.py +464 -0
- pulse_framework-0.1.62/src/pulse/hooks/setup.py +254 -0
- pulse_framework-0.1.62/src/pulse/hooks/stable.py +138 -0
- pulse_framework-0.1.62/src/pulse/hooks/state.py +192 -0
- pulse_framework-0.1.62/src/pulse/js/__init__.py +125 -0
- pulse_framework-0.1.62/src/pulse/js/__init__.pyi +115 -0
- pulse_framework-0.1.62/src/pulse/js/_types.py +299 -0
- pulse_framework-0.1.62/src/pulse/js/array.py +339 -0
- pulse_framework-0.1.62/src/pulse/js/console.py +50 -0
- pulse_framework-0.1.62/src/pulse/js/date.py +119 -0
- pulse_framework-0.1.62/src/pulse/js/document.py +145 -0
- pulse_framework-0.1.62/src/pulse/js/error.py +140 -0
- pulse_framework-0.1.62/src/pulse/js/json.py +66 -0
- pulse_framework-0.1.62/src/pulse/js/map.py +97 -0
- pulse_framework-0.1.62/src/pulse/js/math.py +69 -0
- pulse_framework-0.1.62/src/pulse/js/navigator.py +79 -0
- pulse_framework-0.1.62/src/pulse/js/number.py +57 -0
- pulse_framework-0.1.62/src/pulse/js/obj.py +81 -0
- pulse_framework-0.1.62/src/pulse/js/object.py +172 -0
- pulse_framework-0.1.62/src/pulse/js/promise.py +172 -0
- pulse_framework-0.1.62/src/pulse/js/pulse.py +115 -0
- pulse_framework-0.1.62/src/pulse/js/react.py +495 -0
- pulse_framework-0.1.62/src/pulse/js/regexp.py +57 -0
- pulse_framework-0.1.62/src/pulse/js/set.py +124 -0
- pulse_framework-0.1.62/src/pulse/js/string.py +38 -0
- pulse_framework-0.1.62/src/pulse/js/weakmap.py +53 -0
- pulse_framework-0.1.62/src/pulse/js/weakset.py +48 -0
- pulse_framework-0.1.62/src/pulse/js/window.py +205 -0
- pulse_framework-0.1.62/src/pulse/messages.py +202 -0
- pulse_framework-0.1.62/src/pulse/middleware.py +471 -0
- pulse_framework-0.1.62/src/pulse/plugin.py +96 -0
- pulse_framework-0.1.62/src/pulse/proxy.py +242 -0
- pulse_framework-0.1.62/src/pulse/py.typed +0 -0
- pulse_framework-0.1.62/src/pulse/queries/__init__.py +0 -0
- pulse_framework-0.1.62/src/pulse/queries/client.py +609 -0
- pulse_framework-0.1.62/src/pulse/queries/common.py +101 -0
- pulse_framework-0.1.62/src/pulse/queries/effect.py +55 -0
- pulse_framework-0.1.62/src/pulse/queries/infinite_query.py +1418 -0
- pulse_framework-0.1.62/src/pulse/queries/mutation.py +295 -0
- pulse_framework-0.1.62/src/pulse/queries/protocol.py +136 -0
- pulse_framework-0.1.62/src/pulse/queries/query.py +1314 -0
- pulse_framework-0.1.62/src/pulse/queries/store.py +120 -0
- pulse_framework-0.1.62/src/pulse/react_component.py +88 -0
- pulse_framework-0.1.62/src/pulse/reactive.py +1208 -0
- pulse_framework-0.1.62/src/pulse/reactive_extensions.py +1172 -0
- pulse_framework-0.1.62/src/pulse/render_session.py +768 -0
- pulse_framework-0.1.62/src/pulse/renderer.py +584 -0
- pulse_framework-0.1.62/src/pulse/request.py +205 -0
- pulse_framework-0.1.62/src/pulse/routing.py +598 -0
- pulse_framework-0.1.62/src/pulse/serializer.py +279 -0
- pulse_framework-0.1.62/src/pulse/state.py +556 -0
- pulse_framework-0.1.62/src/pulse/test_helpers.py +15 -0
- pulse_framework-0.1.62/src/pulse/transpiler/__init__.py +111 -0
- pulse_framework-0.1.62/src/pulse/transpiler/assets.py +81 -0
- pulse_framework-0.1.62/src/pulse/transpiler/builtins.py +1029 -0
- pulse_framework-0.1.62/src/pulse/transpiler/dynamic_import.py +130 -0
- pulse_framework-0.1.62/src/pulse/transpiler/emit_context.py +49 -0
- pulse_framework-0.1.62/src/pulse/transpiler/errors.py +96 -0
- pulse_framework-0.1.62/src/pulse/transpiler/function.py +611 -0
- pulse_framework-0.1.62/src/pulse/transpiler/id.py +18 -0
- pulse_framework-0.1.62/src/pulse/transpiler/imports.py +341 -0
- pulse_framework-0.1.62/src/pulse/transpiler/js_module.py +336 -0
- pulse_framework-0.1.62/src/pulse/transpiler/modules/__init__.py +33 -0
- pulse_framework-0.1.62/src/pulse/transpiler/modules/asyncio.py +57 -0
- pulse_framework-0.1.62/src/pulse/transpiler/modules/json.py +24 -0
- pulse_framework-0.1.62/src/pulse/transpiler/modules/math.py +265 -0
- pulse_framework-0.1.62/src/pulse/transpiler/modules/pulse/__init__.py +5 -0
- pulse_framework-0.1.62/src/pulse/transpiler/modules/pulse/tags.py +250 -0
- pulse_framework-0.1.62/src/pulse/transpiler/modules/typing.py +63 -0
- pulse_framework-0.1.62/src/pulse/transpiler/nodes.py +1987 -0
- pulse_framework-0.1.62/src/pulse/transpiler/py_module.py +135 -0
- pulse_framework-0.1.62/src/pulse/transpiler/transpiler.py +1100 -0
- pulse_framework-0.1.62/src/pulse/transpiler/vdom.py +256 -0
- pulse_framework-0.1.62/src/pulse/types/__init__.py +0 -0
- pulse_framework-0.1.62/src/pulse/types/event_handler.py +50 -0
- pulse_framework-0.1.62/src/pulse/user_session.py +386 -0
- pulse_framework-0.1.62/src/pulse/version.py +69 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: pulse-framework
|
|
3
|
+
Version: 0.1.62
|
|
4
|
+
Summary: Pulse - Full-stack framework for building real-time React applications in Python
|
|
5
|
+
Requires-Dist: websockets>=12.0
|
|
6
|
+
Requires-Dist: fastapi>=0.128.0
|
|
7
|
+
Requires-Dist: uvicorn>=0.24.0
|
|
8
|
+
Requires-Dist: mako>=1.3.10
|
|
9
|
+
Requires-Dist: typer>=0.16.0
|
|
10
|
+
Requires-Dist: python-socketio>=5.16.0
|
|
11
|
+
Requires-Dist: rich>=13.7.1
|
|
12
|
+
Requires-Dist: python-multipart>=0.0.20
|
|
13
|
+
Requires-Dist: python-dateutil>=2.9.0.post0
|
|
14
|
+
Requires-Dist: starlette>=0.50.0,<0.51.0
|
|
15
|
+
Requires-Dist: urllib3>=2.6.3
|
|
16
|
+
Requires-Dist: watchfiles>=1.1.0
|
|
17
|
+
Requires-Dist: httpx>=0.28.1
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# Pulse Python
|
|
22
|
+
|
|
23
|
+
Core Python framework for building full-stack reactive web apps with React frontends.
|
|
24
|
+
|
|
25
|
+
## Architecture
|
|
26
|
+
|
|
27
|
+
Server-driven UI model: Python components render to VDOM, synced to React via WebSocket. State changes trigger re-renders; diffs are sent to client.
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
31
|
+
│ Python Server │
|
|
32
|
+
│ ┌──────────┐ ┌───────────────┐ ┌──────────────────────────┐ │
|
|
33
|
+
│ │ App │──│ RenderSession │──│ VDOM Renderer │ │
|
|
34
|
+
│ │ (FastAPI)│ │ (per browser) │ │ (diff & serialize) │ │
|
|
35
|
+
│ └──────────┘ └───────────────┘ └──────────────────────────┘ │
|
|
36
|
+
│ │ │ │ │
|
|
37
|
+
│ │ ┌──────┴───────┐ │ │
|
|
38
|
+
│ │ │ Hooks │ │ │
|
|
39
|
+
│ │ │ (state/setup)│ │ │
|
|
40
|
+
│ │ └──────────────┘ │ │
|
|
41
|
+
└───────┼───────────────────────────────────────┼─────────────────┘
|
|
42
|
+
│ Socket.IO │ VDOM updates
|
|
43
|
+
▼ ▼
|
|
44
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
45
|
+
│ Browser (React) │
|
|
46
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Folder Structure
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
src/pulse/
|
|
53
|
+
├── app.py # Main App class, FastAPI + Socket.IO setup
|
|
54
|
+
├── channel.py # Bidirectional real-time channels
|
|
55
|
+
├── routing.py # Route/Layout definitions, URL matching
|
|
56
|
+
├── vdom.py # VDOM node types (Element, Component, Node)
|
|
57
|
+
├── renderer.py # VDOM rendering and diffing
|
|
58
|
+
├── render_session.py # Per-browser session, manages mounted routes
|
|
59
|
+
├── reactive.py # Signal/Computed/Effect primitives
|
|
60
|
+
├── reactive_extensions.py # ReactiveList, ReactiveDict, ReactiveSet
|
|
61
|
+
├── state.py # State management
|
|
62
|
+
├── serializer.py # Python<->JSON serialization
|
|
63
|
+
├── middleware.py # Request middleware (prerender, connect, message)
|
|
64
|
+
├── plugin.py # Plugin interface for extensions
|
|
65
|
+
├── form.py # Form handling
|
|
66
|
+
├── context.py # PulseContext (request/session context)
|
|
67
|
+
├── cookies.py # Cookie management
|
|
68
|
+
├── request.py # PulseRequest abstraction
|
|
69
|
+
├── user_session.py # User session storage
|
|
70
|
+
├── helpers.py # Utilities (CSSProperties, later, repeat)
|
|
71
|
+
├── decorators.py # @computed, @effect decorators
|
|
72
|
+
├── messages.py # Client<->server message types
|
|
73
|
+
├── react_component.py # ReactComponent wrapper for JS libraries
|
|
74
|
+
│
|
|
75
|
+
├── hooks/ # Server-side hooks (like React hooks)
|
|
76
|
+
│ ├── core.py # Hook registry, HooksAPI
|
|
77
|
+
│ ├── runtime.py # session(), route(), navigate(), redirect()
|
|
78
|
+
│ ├── states.py # Reactive state hook
|
|
79
|
+
│ ├── effects.py # Side effects hook
|
|
80
|
+
│ ├── setup.py # Initialization hook
|
|
81
|
+
│ ├── init.py # One-time setup hook
|
|
82
|
+
│ └── stable.py # Memoization hook
|
|
83
|
+
│
|
|
84
|
+
├── queries/ # Data fetching (like TanStack Query)
|
|
85
|
+
│ ├── query.py # @query decorator
|
|
86
|
+
│ ├── mutation.py # @mutation decorator
|
|
87
|
+
│ ├── infinite_query.py # Pagination support
|
|
88
|
+
│ ├── client.py # QueryClient for cache management
|
|
89
|
+
│ └── store.py # Query state store
|
|
90
|
+
│
|
|
91
|
+
├── components/ # Built-in components
|
|
92
|
+
│ ├── for_.py # <For> loop component
|
|
93
|
+
│ ├── if_.py # <If> conditional component
|
|
94
|
+
│ └── react_router.py # Link, Outlet for routing
|
|
95
|
+
│
|
|
96
|
+
├── html/ # HTML element bindings
|
|
97
|
+
│ ├── tags.py # div, span, button, etc.
|
|
98
|
+
│ ├── props.py # Typed props for HTML elements
|
|
99
|
+
│ ├── events.py # Event types (MouseEvent, etc.)
|
|
100
|
+
│ └── elements.py # Element type definitions
|
|
101
|
+
│
|
|
102
|
+
├── transpiler/ # Python->JS transpilation
|
|
103
|
+
│ ├── function.py # JsFunction, @javascript decorator
|
|
104
|
+
│ └── imports.py # Import/CssImport for client-side JS
|
|
105
|
+
│
|
|
106
|
+
├── codegen/ # Code generation for React Router
|
|
107
|
+
│ ├── codegen.py # Generates routes.ts, loaders
|
|
108
|
+
│ └── templates/ # Mako templates for generated code
|
|
109
|
+
│
|
|
110
|
+
├── cli/ # Command-line interface
|
|
111
|
+
│ ├── cmd.py # pulse run, pulse build
|
|
112
|
+
│ └── processes.py # Dev server process management
|
|
113
|
+
│
|
|
114
|
+
└── js/ # JS API stubs for transpilation
|
|
115
|
+
├── window.py, document.py, navigator.py
|
|
116
|
+
├── array.py, object.py, string.py
|
|
117
|
+
└── ...
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Key Concepts
|
|
121
|
+
|
|
122
|
+
### App
|
|
123
|
+
|
|
124
|
+
Entry point defining routes, middleware, plugins.
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
import pulse as ps
|
|
128
|
+
|
|
129
|
+
app = ps.App(routes=[
|
|
130
|
+
ps.Route("/", home),
|
|
131
|
+
ps.Layout("/dashboard", layout, children=[
|
|
132
|
+
ps.Route("/", dashboard),
|
|
133
|
+
]),
|
|
134
|
+
])
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Components
|
|
138
|
+
|
|
139
|
+
Functions returning VDOM. Use `@ps.component` for stateful components.
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
def greeting(name: str):
|
|
143
|
+
return ps.div(f"Hello, {name}!")
|
|
144
|
+
|
|
145
|
+
@ps.component
|
|
146
|
+
def counter():
|
|
147
|
+
count = ps.states.use(0)
|
|
148
|
+
return ps.button(f"Count: {count()}", onClick=lambda _: count.set(count() + 1))
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Reactivity
|
|
152
|
+
|
|
153
|
+
- `Signal[T]` - reactive value
|
|
154
|
+
- `Computed[T]` - derived value
|
|
155
|
+
- `Effect` - side effect on change
|
|
156
|
+
|
|
157
|
+
### Hooks
|
|
158
|
+
|
|
159
|
+
Server-side hooks via `ps.state`, `ps.effect`, `ps.setup`:
|
|
160
|
+
- `ps.state(StateClass)` - reactive state (auto-keyed by callsite; use `key=` for manual control)
|
|
161
|
+
- `@ps.effect` - side effects decorator
|
|
162
|
+
- `ps.setup(fn)` - one-time initialization
|
|
163
|
+
|
|
164
|
+
### Queries
|
|
165
|
+
|
|
166
|
+
Data fetching with caching:
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
@ps.query
|
|
170
|
+
async def fetch_user(id: str):
|
|
171
|
+
return await db.get_user(id)
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Channels
|
|
175
|
+
|
|
176
|
+
Bidirectional real-time messaging:
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
ch = ps.channel("chat")
|
|
180
|
+
|
|
181
|
+
@ch.on("message")
|
|
182
|
+
def handle_message(data):
|
|
183
|
+
ch.broadcast("new_message", data)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Main Exports
|
|
187
|
+
|
|
188
|
+
- `App`, `Route`, `Layout` - app/routing
|
|
189
|
+
- `component` - server-side component decorator
|
|
190
|
+
- `states`, `effects`, `setup`, `init` - hooks
|
|
191
|
+
- `query`, `mutation`, `infinite_query` - data fetching
|
|
192
|
+
- `channel` - real-time channels
|
|
193
|
+
- `State`, `@computed`, `@effect` - reactivity
|
|
194
|
+
- `ReactiveList`, `ReactiveDict`, `ReactiveSet` - reactive containers
|
|
195
|
+
- `div`, `span`, `button`, ... - HTML elements
|
|
196
|
+
- `For`, `If`, `Link`, `Outlet` - built-in components
|
|
197
|
+
- `@react_component` - wrap JS components
|
|
198
|
+
- `@javascript` - transpile Python to JS
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# Pulse Python
|
|
2
|
+
|
|
3
|
+
Core Python framework for building full-stack reactive web apps with React frontends.
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
Server-driven UI model: Python components render to VDOM, synced to React via WebSocket. State changes trigger re-renders; diffs are sent to client.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
11
|
+
│ Python Server │
|
|
12
|
+
│ ┌──────────┐ ┌───────────────┐ ┌──────────────────────────┐ │
|
|
13
|
+
│ │ App │──│ RenderSession │──│ VDOM Renderer │ │
|
|
14
|
+
│ │ (FastAPI)│ │ (per browser) │ │ (diff & serialize) │ │
|
|
15
|
+
│ └──────────┘ └───────────────┘ └──────────────────────────┘ │
|
|
16
|
+
│ │ │ │ │
|
|
17
|
+
│ │ ┌──────┴───────┐ │ │
|
|
18
|
+
│ │ │ Hooks │ │ │
|
|
19
|
+
│ │ │ (state/setup)│ │ │
|
|
20
|
+
│ │ └──────────────┘ │ │
|
|
21
|
+
└───────┼───────────────────────────────────────┼─────────────────┘
|
|
22
|
+
│ Socket.IO │ VDOM updates
|
|
23
|
+
▼ ▼
|
|
24
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
25
|
+
│ Browser (React) │
|
|
26
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Folder Structure
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
src/pulse/
|
|
33
|
+
├── app.py # Main App class, FastAPI + Socket.IO setup
|
|
34
|
+
├── channel.py # Bidirectional real-time channels
|
|
35
|
+
├── routing.py # Route/Layout definitions, URL matching
|
|
36
|
+
├── vdom.py # VDOM node types (Element, Component, Node)
|
|
37
|
+
├── renderer.py # VDOM rendering and diffing
|
|
38
|
+
├── render_session.py # Per-browser session, manages mounted routes
|
|
39
|
+
├── reactive.py # Signal/Computed/Effect primitives
|
|
40
|
+
├── reactive_extensions.py # ReactiveList, ReactiveDict, ReactiveSet
|
|
41
|
+
├── state.py # State management
|
|
42
|
+
├── serializer.py # Python<->JSON serialization
|
|
43
|
+
├── middleware.py # Request middleware (prerender, connect, message)
|
|
44
|
+
├── plugin.py # Plugin interface for extensions
|
|
45
|
+
├── form.py # Form handling
|
|
46
|
+
├── context.py # PulseContext (request/session context)
|
|
47
|
+
├── cookies.py # Cookie management
|
|
48
|
+
├── request.py # PulseRequest abstraction
|
|
49
|
+
├── user_session.py # User session storage
|
|
50
|
+
├── helpers.py # Utilities (CSSProperties, later, repeat)
|
|
51
|
+
├── decorators.py # @computed, @effect decorators
|
|
52
|
+
├── messages.py # Client<->server message types
|
|
53
|
+
├── react_component.py # ReactComponent wrapper for JS libraries
|
|
54
|
+
│
|
|
55
|
+
├── hooks/ # Server-side hooks (like React hooks)
|
|
56
|
+
│ ├── core.py # Hook registry, HooksAPI
|
|
57
|
+
│ ├── runtime.py # session(), route(), navigate(), redirect()
|
|
58
|
+
│ ├── states.py # Reactive state hook
|
|
59
|
+
│ ├── effects.py # Side effects hook
|
|
60
|
+
│ ├── setup.py # Initialization hook
|
|
61
|
+
│ ├── init.py # One-time setup hook
|
|
62
|
+
│ └── stable.py # Memoization hook
|
|
63
|
+
│
|
|
64
|
+
├── queries/ # Data fetching (like TanStack Query)
|
|
65
|
+
│ ├── query.py # @query decorator
|
|
66
|
+
│ ├── mutation.py # @mutation decorator
|
|
67
|
+
│ ├── infinite_query.py # Pagination support
|
|
68
|
+
│ ├── client.py # QueryClient for cache management
|
|
69
|
+
│ └── store.py # Query state store
|
|
70
|
+
│
|
|
71
|
+
├── components/ # Built-in components
|
|
72
|
+
│ ├── for_.py # <For> loop component
|
|
73
|
+
│ ├── if_.py # <If> conditional component
|
|
74
|
+
│ └── react_router.py # Link, Outlet for routing
|
|
75
|
+
│
|
|
76
|
+
├── html/ # HTML element bindings
|
|
77
|
+
│ ├── tags.py # div, span, button, etc.
|
|
78
|
+
│ ├── props.py # Typed props for HTML elements
|
|
79
|
+
│ ├── events.py # Event types (MouseEvent, etc.)
|
|
80
|
+
│ └── elements.py # Element type definitions
|
|
81
|
+
│
|
|
82
|
+
├── transpiler/ # Python->JS transpilation
|
|
83
|
+
│ ├── function.py # JsFunction, @javascript decorator
|
|
84
|
+
│ └── imports.py # Import/CssImport for client-side JS
|
|
85
|
+
│
|
|
86
|
+
├── codegen/ # Code generation for React Router
|
|
87
|
+
│ ├── codegen.py # Generates routes.ts, loaders
|
|
88
|
+
│ └── templates/ # Mako templates for generated code
|
|
89
|
+
│
|
|
90
|
+
├── cli/ # Command-line interface
|
|
91
|
+
│ ├── cmd.py # pulse run, pulse build
|
|
92
|
+
│ └── processes.py # Dev server process management
|
|
93
|
+
│
|
|
94
|
+
└── js/ # JS API stubs for transpilation
|
|
95
|
+
├── window.py, document.py, navigator.py
|
|
96
|
+
├── array.py, object.py, string.py
|
|
97
|
+
└── ...
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Key Concepts
|
|
101
|
+
|
|
102
|
+
### App
|
|
103
|
+
|
|
104
|
+
Entry point defining routes, middleware, plugins.
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
import pulse as ps
|
|
108
|
+
|
|
109
|
+
app = ps.App(routes=[
|
|
110
|
+
ps.Route("/", home),
|
|
111
|
+
ps.Layout("/dashboard", layout, children=[
|
|
112
|
+
ps.Route("/", dashboard),
|
|
113
|
+
]),
|
|
114
|
+
])
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Components
|
|
118
|
+
|
|
119
|
+
Functions returning VDOM. Use `@ps.component` for stateful components.
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
def greeting(name: str):
|
|
123
|
+
return ps.div(f"Hello, {name}!")
|
|
124
|
+
|
|
125
|
+
@ps.component
|
|
126
|
+
def counter():
|
|
127
|
+
count = ps.states.use(0)
|
|
128
|
+
return ps.button(f"Count: {count()}", onClick=lambda _: count.set(count() + 1))
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Reactivity
|
|
132
|
+
|
|
133
|
+
- `Signal[T]` - reactive value
|
|
134
|
+
- `Computed[T]` - derived value
|
|
135
|
+
- `Effect` - side effect on change
|
|
136
|
+
|
|
137
|
+
### Hooks
|
|
138
|
+
|
|
139
|
+
Server-side hooks via `ps.state`, `ps.effect`, `ps.setup`:
|
|
140
|
+
- `ps.state(StateClass)` - reactive state (auto-keyed by callsite; use `key=` for manual control)
|
|
141
|
+
- `@ps.effect` - side effects decorator
|
|
142
|
+
- `ps.setup(fn)` - one-time initialization
|
|
143
|
+
|
|
144
|
+
### Queries
|
|
145
|
+
|
|
146
|
+
Data fetching with caching:
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
@ps.query
|
|
150
|
+
async def fetch_user(id: str):
|
|
151
|
+
return await db.get_user(id)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Channels
|
|
155
|
+
|
|
156
|
+
Bidirectional real-time messaging:
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
ch = ps.channel("chat")
|
|
160
|
+
|
|
161
|
+
@ch.on("message")
|
|
162
|
+
def handle_message(data):
|
|
163
|
+
ch.broadcast("new_message", data)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Main Exports
|
|
167
|
+
|
|
168
|
+
- `App`, `Route`, `Layout` - app/routing
|
|
169
|
+
- `component` - server-side component decorator
|
|
170
|
+
- `states`, `effects`, `setup`, `init` - hooks
|
|
171
|
+
- `query`, `mutation`, `infinite_query` - data fetching
|
|
172
|
+
- `channel` - real-time channels
|
|
173
|
+
- `State`, `@computed`, `@effect` - reactivity
|
|
174
|
+
- `ReactiveList`, `ReactiveDict`, `ReactiveSet` - reactive containers
|
|
175
|
+
- `div`, `span`, `button`, ... - HTML elements
|
|
176
|
+
- `For`, `If`, `Link`, `Outlet` - built-in components
|
|
177
|
+
- `@react_component` - wrap JS components
|
|
178
|
+
- `@javascript` - transpile Python to JS
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "pulse-framework"
|
|
3
|
+
version = "0.1.62"
|
|
4
|
+
description = "Pulse - Full-stack framework for building real-time React applications in Python"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"websockets>=12.0",
|
|
9
|
+
"fastapi>=0.128.0",
|
|
10
|
+
"uvicorn>=0.24.0",
|
|
11
|
+
"mako>=1.3.10",
|
|
12
|
+
"typer>=0.16.0",
|
|
13
|
+
"python-socketio>=5.16.0",
|
|
14
|
+
"rich>=13.7.1",
|
|
15
|
+
"python-multipart>=0.0.20",
|
|
16
|
+
"python-dateutil>=2.9.0.post0",
|
|
17
|
+
"starlette>=0.50.0,<0.51.0",
|
|
18
|
+
"urllib3>=2.6.3",
|
|
19
|
+
"watchfiles>=1.1.0",
|
|
20
|
+
"httpx>=0.28.1",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[tool.uv]
|
|
24
|
+
package = true
|
|
25
|
+
|
|
26
|
+
[tool.uv.build-backend]
|
|
27
|
+
module-name = "pulse"
|
|
28
|
+
|
|
29
|
+
[project.scripts]
|
|
30
|
+
pulse = "pulse.cli.cmd:main"
|
|
31
|
+
|
|
32
|
+
[dependency-groups]
|
|
33
|
+
dev = ["mypy>=1.17.0", "pytest>=8.3.4", "pytest-asyncio>=1.1.0"]
|
|
34
|
+
|
|
35
|
+
[build-system]
|
|
36
|
+
requires = ["uv_build>=0.8.13,<0.9.0"]
|
|
37
|
+
build-backend = "uv_build"
|