pyweb-stack 0.4.0__tar.gz → 0.4.1__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.
Files changed (118) hide show
  1. pyweb_stack-0.4.1/PKG-INFO +400 -0
  2. pyweb_stack-0.4.1/README.md +346 -0
  3. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyproject.toml +1 -1
  4. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/ai/guide.md +160 -39
  5. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/compiler/parser.py +13 -1
  6. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/mcp.py +153 -16
  7. pyweb_stack-0.4.1/pyweb_stack.egg-info/PKG-INFO +400 -0
  8. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_mcp.py +73 -2
  9. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_parser_v1.py +7 -0
  10. pyweb_stack-0.4.0/PKG-INFO +0 -252
  11. pyweb_stack-0.4.0/README.md +0 -198
  12. pyweb_stack-0.4.0/pyweb_stack.egg-info/PKG-INFO +0 -252
  13. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/LICENSE +0 -0
  14. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/__init__.py +0 -0
  15. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/app.py +0 -0
  16. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/app_loader.py +0 -0
  17. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/asgi.py +0 -0
  18. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/auth.py +0 -0
  19. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/bench.py +0 -0
  20. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/browser.py +0 -0
  21. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/build.py +0 -0
  22. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/cache.py +0 -0
  23. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/cli/__init__.py +0 -0
  24. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/cli/__main__.py +0 -0
  25. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/compiler/__init__.py +0 -0
  26. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/compiler/ast.py +0 -0
  27. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/compiler/codegen/__init__.py +0 -0
  28. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/compiler/codegen/ir.py +0 -0
  29. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/compiler/errors.py +0 -0
  30. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/compiler/lower.py +0 -0
  31. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/compiler/pipeline.py +0 -0
  32. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/compiler/pyjs.py +0 -0
  33. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/compiler/rpc.py +0 -0
  34. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/context.py +0 -0
  35. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/css.py +0 -0
  36. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/db/__init__.py +0 -0
  37. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/db/migrate.py +0 -0
  38. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/decorators.py +0 -0
  39. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/deploy.py +0 -0
  40. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/dts.py +0 -0
  41. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/forms.py +0 -0
  42. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/hosting.py +0 -0
  43. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/jobs.py +0 -0
  44. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/livedata.py +0 -0
  45. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/livetable.py +0 -0
  46. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/lsp.py +0 -0
  47. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/markdown.py +0 -0
  48. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/models.py +0 -0
  49. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/observability.py +0 -0
  50. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/packages.py +0 -0
  51. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/platform.py +0 -0
  52. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/plugins.py +0 -0
  53. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/py.typed +0 -0
  54. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/realtime.py +0 -0
  55. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/rpc.py +0 -0
  56. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/runtime/browser/markdown.js +0 -0
  57. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/runtime/browser/runtime.js +0 -0
  58. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/runtime/server/__init__.py +0 -0
  59. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/security.py +0 -0
  60. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/serve.py +0 -0
  61. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/ssr.py +0 -0
  62. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/sync.py +0 -0
  63. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/templates/ai-chat.pyweb +0 -0
  64. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/templates/app.css +0 -0
  65. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/templates/auth.pyweb +0 -0
  66. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/templates/blog.pyweb +0 -0
  67. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/templates/chat.pyweb +0 -0
  68. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/templates/counter.pyweb +0 -0
  69. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/templates/todo.pyweb +0 -0
  70. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/testing.py +0 -0
  71. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb/uploads.py +0 -0
  72. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb_stack.egg-info/SOURCES.txt +0 -0
  73. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb_stack.egg-info/dependency_links.txt +0 -0
  74. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb_stack.egg-info/entry_points.txt +0 -0
  75. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb_stack.egg-info/requires.txt +0 -0
  76. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/pyweb_stack.egg-info/top_level.txt +0 -0
  77. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/setup.cfg +0 -0
  78. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_auth.py +0 -0
  79. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_auth_contract.py +0 -0
  80. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_auth_security.py +0 -0
  81. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_auth_v1.py +0 -0
  82. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_backplane.py +0 -0
  83. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_browser_build.py +0 -0
  84. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_budget.py +0 -0
  85. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_cli_deploy.py +0 -0
  86. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_codegen.py +0 -0
  87. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_compiler.py +0 -0
  88. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_db_production.py +0 -0
  89. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_deploy_upload_render.py +0 -0
  90. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_docs.py +0 -0
  91. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_dts.py +0 -0
  92. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_e2e.py +0 -0
  93. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_examples.py +0 -0
  94. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_forms_security_obs.py +0 -0
  95. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_jobs_cache_realtime.py +0 -0
  96. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_livedata.py +0 -0
  97. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_lsp.py +0 -0
  98. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_markdown.py +0 -0
  99. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_models_db.py +0 -0
  100. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_multifile.py +0 -0
  101. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_multipage.py +0 -0
  102. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_observability.py +0 -0
  103. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_packages.py +0 -0
  104. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_parser.py +0 -0
  105. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_plugins_platform_bench.py +0 -0
  106. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_production_gaps.py +0 -0
  107. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_pyjs_semantics.py +0 -0
  108. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_reactivity.py +0 -0
  109. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_realtime_transport.py +0 -0
  110. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_reference_apps.py +0 -0
  111. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_rpc_placement.py +0 -0
  112. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_rpc_production.py +0 -0
  113. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_runtime_signals.py +0 -0
  114. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_server_db.py +0 -0
  115. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_static_hashing.py +0 -0
  116. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_streaming.py +0 -0
  117. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_sync_live.py +0 -0
  118. {pyweb_stack-0.4.0 → pyweb_stack-0.4.1}/tests/test_website.py +0 -0
@@ -0,0 +1,400 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyweb-stack
3
+ Version: 0.4.1
4
+ Summary: Full-stack web apps in one Python file: server-rendered pages, reactive browser UI, typed RPC.
5
+ Author-email: MaanavKrishna <67054795+MaanavKrishna@users.noreply.github.com>
6
+ Maintainer-email: MaanavKrishna <67054795+MaanavKrishna@users.noreply.github.com>
7
+ License: MIT
8
+ Project-URL: Homepage, https://maanavkrishna.github.io/PyWeb/
9
+ Project-URL: Documentation, https://maanavkrishna.github.io/PyWeb/guide.html
10
+ Project-URL: Source, https://github.com/MaanavKrishna/PyWeb
11
+ Project-URL: Changelog, https://github.com/MaanavKrishna/PyWeb/blob/main/CHANGELOG.md
12
+ Project-URL: Issues, https://github.com/MaanavKrishna/PyWeb/issues
13
+ Keywords: web,framework,full-stack,reactive,rpc,ssr,compiler
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Environment :: Web Environment
16
+ Classifier: Framework :: AsyncIO
17
+ Classifier: Intended Audience :: Developers
18
+ Classifier: License :: OSI Approved :: MIT License
19
+ Classifier: Operating System :: OS Independent
20
+ Classifier: Programming Language :: JavaScript
21
+ Classifier: Programming Language :: Python :: 3
22
+ Classifier: Programming Language :: Python :: 3 :: Only
23
+ Classifier: Programming Language :: Python :: 3.10
24
+ Classifier: Programming Language :: Python :: 3.11
25
+ Classifier: Programming Language :: Python :: 3.12
26
+ Classifier: Programming Language :: Python :: 3.13
27
+ Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
28
+ Classifier: Topic :: Software Development :: Compilers
29
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
30
+ Requires-Python: >=3.10
31
+ Description-Content-Type: text/markdown
32
+ License-File: LICENSE
33
+ Provides-Extra: postgres
34
+ Requires-Dist: psycopg[binary]>=3.1; extra == "postgres"
35
+ Provides-Extra: mysql
36
+ Requires-Dist: PyMySQL>=1.1; extra == "mysql"
37
+ Provides-Extra: redis
38
+ Requires-Dist: redis>=5; extra == "redis"
39
+ Provides-Extra: crypto
40
+ Requires-Dist: cryptography>=42; extra == "crypto"
41
+ Provides-Extra: asgi
42
+ Requires-Dist: uvicorn>=0.30; extra == "asgi"
43
+ Provides-Extra: all
44
+ Requires-Dist: psycopg[binary]>=3.1; extra == "all"
45
+ Requires-Dist: PyMySQL>=1.1; extra == "all"
46
+ Requires-Dist: redis>=5; extra == "all"
47
+ Requires-Dist: cryptography>=42; extra == "all"
48
+ Requires-Dist: uvicorn>=0.30; extra == "all"
49
+ Provides-Extra: test
50
+ Requires-Dist: pytest>=8; extra == "test"
51
+ Requires-Dist: playwright>=1.45; extra == "test"
52
+ Requires-Dist: mcp>=1.2; extra == "test"
53
+ Dynamic: license-file
54
+
55
+ <div align="center">
56
+
57
+ # PyWeb
58
+
59
+ **Full-stack web apps in one Python file.**
60
+
61
+ Server-rendered pages, a reactive UI compiled from Python, typed calls to
62
+ your server, live data and streaming AI, with no JavaScript toolchain.
63
+
64
+ [![CI](https://github.com/MaanavKrishna/PyWeb/actions/workflows/ci.yml/badge.svg)](https://github.com/MaanavKrishna/PyWeb/actions/workflows/ci.yml)
65
+ [![PyPI](https://img.shields.io/pypi/v/pyweb-stack)](https://pypi.org/project/pyweb-stack/)
66
+ ![Python](https://img.shields.io/badge/python-3.10%E2%80%933.13-3776ab)
67
+ [![Docs](https://img.shields.io/badge/docs-maanavkrishna.github.io%2FPyWeb-0d9488)](https://maanavkrishna.github.io/PyWeb/)
68
+ ![License](https://img.shields.io/badge/license-MIT-lightgrey)
69
+
70
+ **[Documentation](https://maanavkrishna.github.io/PyWeb/)** ·
71
+ **[Try it in your browser](https://maanavkrishna.github.io/PyWeb/playground.html)** ·
72
+ **[Examples](#examples)** ·
73
+ **[Changelog](CHANGELOG.md)**
74
+
75
+ </div>
76
+
77
+ ```pyweb
78
+ from pyweb import App, server
79
+
80
+ app = App(title="Guestbook")
81
+ ENTRIES = []
82
+
83
+
84
+ @server
85
+ def sign(name: str) -> list:
86
+ ENTRIES.append(name.strip() or "anonymous")
87
+ return ENTRIES
88
+
89
+
90
+ @app.page("/")
91
+ def Home():
92
+ entries = list(ENTRIES) # computed on the server per request
93
+ name = "" # bound to the input: browser state
94
+
95
+ def submit(): # compiled to JavaScript
96
+ entries = sign(name) # typed RPC to the server
97
+ name = ""
98
+
99
+ <main>
100
+ <h1>Guestbook ({len(entries)})</h1>
101
+ <form onsubmit={submit}>
102
+ <input bind={name} placeholder="Your name" />
103
+ <button>Sign</button>
104
+ </form>
105
+ <ul>
106
+ for entry in entries:
107
+ <li>{entry}</li>
108
+ </ul>
109
+ </main>
110
+ ```
111
+
112
+ ```bash
113
+ pip install pyweb-stack # imported as `pyweb`
114
+ pyweb dev app.pyweb # http://localhost:8000, with live reload
115
+ ```
116
+
117
+ That's the whole app. The page is rendered on the server with real data,
118
+ the handler becomes a few hundred bytes of JavaScript, and `sign()` becomes
119
+ a validated JSON endpoint the browser calls for you.
120
+
121
+ ## What you get
122
+
123
+ ### Python on both sides, split by the compiler
124
+
125
+ You write one file. The compiler decides, line by line, what runs in the
126
+ browser and what stays on the server, and tells you why
127
+ (`pyweb inspect`). Variables your handlers change become reactive state;
128
+ everything else is computed on the server. Database handles, imports and
129
+ secrets can't leak into browser code: that's a compile error with a line
130
+ number, not a production incident.
131
+
132
+ ### Pages that follow the database
133
+
134
+ ```pyweb
135
+ from pyweb import App, live
136
+ from pyweb.db import connect
137
+
138
+ app = App()
139
+ db = connect("sqlite:///shop.db")
140
+
141
+
142
+ @app.page("/orders")
143
+ def Orders():
144
+ orders = live(db, "select item, status from orders order by id desc limit 20")
145
+
146
+ <ul>
147
+ for o in orders:
148
+ <li>{o["item"]}: {o["status"]}</li>
149
+ </ul>
150
+ ```
151
+
152
+ Any write through `pyweb.db` updates every open window. Identical queries
153
+ run once for all viewers, and it works across processes with Redis.
154
+ [Live data →](docs/21-live-data.md)
155
+
156
+ ### AI features that stream
157
+
158
+ ```pyweb
159
+ from pyweb import App, Markdown, server
160
+
161
+ app = App()
162
+
163
+
164
+ @server
165
+ def answer(question: str):
166
+ for piece in ("**Streaming**", " from", " the", " server."): # your model's tokens
167
+ yield piece
168
+
169
+
170
+ @app.page("/")
171
+ def Ask():
172
+ question = ""
173
+ reply = ""
174
+ stream = None
175
+
176
+ async def ask():
177
+ reply = ""
178
+ stream = answer(question)
179
+ async for piece in stream:
180
+ reply += piece
181
+
182
+ def stop():
183
+ if stream:
184
+ stream.cancel()
185
+
186
+ <input bind={question} />
187
+ <button onclick={ask}>Ask</button>
188
+ <button onclick={stop}>Stop</button>
189
+ <Markdown text={reply} />
190
+ ```
191
+
192
+ `yield` on the server, `async for` in the browser. Stop really stops:
193
+ the generator on the server is closed, so the model call ends too.
194
+ `<Markdown>` is safe on model output. Start from
195
+ `pyweb new mychat --template ai-chat` (Anthropic, any OpenAI-compatible
196
+ server, or a built-in demo model). [Building AI apps →](docs/20-ai-apps.md)
197
+
198
+ ### Real multi-page apps
199
+
200
+ ```pyweb
201
+ from pyweb import App
202
+
203
+ app = App(title="Plant shop")
204
+
205
+
206
+ @app.layout
207
+ def Shell(children):
208
+ cart = 0
209
+
210
+ def add():
211
+ cart += 1
212
+
213
+ <nav><a href="/">Home</a> <a href="/plants">Plants</a> <button onclick={add}>Cart {cart}</button></nav>
214
+ {children}
215
+
216
+
217
+ @app.page("/plants", description="Every plant we sell")
218
+ def Plants(light: str = "", max_price: int = 0): # typed query parameters
219
+ <h1>Plants</h1>
220
+ ```
221
+
222
+ Layouts keep their state while links load without a full page reload
223
+ (with prefetching and scroll restore). Links to the current page are
224
+ marked automatically, every page gets its own title, description and
225
+ social tags, and 404/500 pages are written in `.pyweb` too.
226
+ [Layouts & navigation →](docs/19-layouts-navigation.md)
227
+
228
+ ### npm packages, without Node.js
229
+
230
+ ```bash
231
+ pyweb add chart.js/auto
232
+ ```
233
+
234
+ ```python
235
+ Chart = npm("chart.js/auto")
236
+ ```
237
+
238
+ PyWeb downloads the package from the npm registry, checks its checksum,
239
+ keeps only the files the browser loads and pins them in `pyweb.lock`.
240
+ There's no `node_modules` and no bundler, and pages that don't use a
241
+ package don't load it. [npm packages →](docs/18-npm-packages.md)
242
+
243
+ ### Small, fast and boring to run
244
+
245
+ - **Every page is server-rendered**: complete HTML on first paint, then
246
+ hydrated in place. Pages without interactivity ship no JavaScript.
247
+ - **Small**: a typical interactive page is under 1 KB of code plus a
248
+ ~15 KB (gzip) runtime that's cached across pages.
249
+ - **Stateless servers**: signed-cookie sessions and plain JSON over HTTP
250
+ scale behind any load balancer. Run `pyweb serve`, uvicorn/gunicorn
251
+ (ASGI) or the generated Dockerfile.
252
+ - **Secure defaults**: escaped output, a strict Content Security Policy,
253
+ CSRF and origin checks on RPC, rate limits and request size limits.
254
+
255
+ ## See it
256
+
257
+ | [Live dashboard](examples/dashboard/app.pyweb) | [Streaming AI chat](examples/ai-chat/app.pyweb) | [Multi-page site](examples/site/app.pyweb) |
258
+ |---|---|---|
259
+ | ![Sales dashboard: totals and a Chart.js bar chart that update live](https://raw.githubusercontent.com/MaanavKrishna/PyWeb/main/docs/images/dashboard.png) | ![AI chat with a streamed Markdown reply](https://raw.githubusercontent.com/MaanavKrishna/PyWeb/main/docs/images/ai-chat.png) | ![Plant shop with a navigation layout and a cart](https://raw.githubusercontent.com/MaanavKrishna/PyWeb/main/docs/images/site.png) |
260
+ | `live()` queries + Chart.js from npm | `yield` + Stop + `<Markdown>` | layout, query parameters, 404 page |
261
+
262
+ Or open the **[playground](https://maanavkrishna.github.io/PyWeb/playground.html)**:
263
+ it runs the real PyWeb, server functions included, in your browser.
264
+
265
+ ## Quick start
266
+
267
+ ```bash
268
+ pip install pyweb-stack
269
+ pyweb new myapp --template todo # blank | counter | todo | blog | auth | chat | ai-chat
270
+ cd myapp
271
+ pyweb dev app.pyweb # edit app.pyweb; the page reloads on save
272
+ ```
273
+
274
+ Then:
275
+
276
+ ```bash
277
+ pyweb check app.pyweb # compile + security checks (CI-friendly exit codes)
278
+ pytest # new apps come with test_app.py
279
+ pyweb build app.pyweb --production # hashed, minified, self-contained dist/
280
+ pyweb serve dist # production server
281
+ ```
282
+
283
+ The [quickstart](docs/02-quickstart.md) and [tutorial](docs/03-tutorial.md)
284
+ take it from there.
285
+
286
+ ## How it works
287
+
288
+ ```text
289
+ app.pyweb
290
+ │
291
+ ┌───────┴────────┐ compiler: parses Python + markup, decides
292
+ ▼ ▼ where each name runs, checks the boundary
293
+ ┌─────────────────┐ ┌─────────────────────────┐
294
+ │ browser module │ │ server │
295
+ │ signals, DOM │ │ page bodies, @server │
296
+ │ updates, your │ │ functions, database, │
297
+ │ handlers in JS │ │ sessions, secrets │
298
+ └────────┬────────┘ └────────────┬────────────┘
299
+ └──── typed JSON RPC ────┘
300
+ (streams and live updates over the same HTTP)
301
+ ```
302
+
303
+ The [architecture overview](ARCHITECTURE.md) goes through each stage.
304
+
305
+ ## Build it with AI
306
+
307
+ PyWeb ships an MCP server so AI assistants can scaffold, check, inspect,
308
+ render, screenshot and test your app, add npm packages, and map its
309
+ routes. Errors come back as line numbers with fix hints:
310
+
311
+ ```bash
312
+ claude mcp add pyweb -- pyweb mcp # Claude Code
313
+ ```
314
+
315
+ ```json
316
+ { "mcpServers": { "pyweb": { "command": "pyweb", "args": ["mcp"] } } }
317
+ ```
318
+
319
+ (the JSON is for Cursor, Claude Desktop, VS Code, Windsurf and other MCP
320
+ clients). New projects include `AGENTS.md` and `CLAUDE.md`, and the docs
321
+ site publishes [`llms-full.txt`](https://maanavkrishna.github.io/PyWeb/llms-full.txt).
322
+ [AI assistants & MCP →](docs/17-ai-assistants.md)
323
+
324
+ ## Editor support
325
+
326
+ The **[VS Code extension](editors/vscode)** adds highlighting, errors as
327
+ you type, hover that shows where code runs (and the signatures of npm
328
+ packages), completion and go to definition. Any other LSP editor can run
329
+ `pyweb lsp` ([setup](docs/14-cli.md#editor-support)).
330
+
331
+ ## Examples
332
+
333
+ Each runs with `pyweb dev examples/<name>/app.pyweb` and is tested in a
334
+ real browser by the test suite.
335
+
336
+ | Example | Shows |
337
+ |---|---|
338
+ | [`counter`](examples/counter/app.pyweb) | signals, computed values, binding a number input |
339
+ | [`todo`](examples/todo/app.pyweb) | components, list mutation, filters, keyed lists |
340
+ | [`blog`](examples/blog/app.pyweb) | SQL database, server functions, route parameters, 404s, validation errors |
341
+ | [`auth`](examples/auth/app.pyweb) | registration, password hashing, sessions, protected pages |
342
+ | [`chat`](examples/chat/app.pyweb) | route parameters, shared server state, live updates with `publish`/`subscribe` |
343
+ | [`showcase`](examples/showcase/app.pyweb) | everything on one page, with a stylesheet |
344
+ | [`site`](examples/site/app.pyweb) | a layout, client-side navigation, query parameters, page titles, a 404 page |
345
+ | [`dashboard`](examples/dashboard/app.pyweb) | live queries and a Chart.js chart from npm, in every open window |
346
+ | [`ai-chat`](examples/ai-chat/app.pyweb) | streaming AI replies with Stop and Markdown (Anthropic, OpenAI-compatible or a demo model) |
347
+
348
+ ## Documentation
349
+
350
+ | | |
351
+ |---|---|
352
+ | Start | [Introduction](docs/01-introduction.md) · [Quickstart](docs/02-quickstart.md) · [Tutorial](docs/03-tutorial.md) · [AI assistants & MCP](docs/17-ai-assistants.md) |
353
+ | Language | [`.pyweb` files](docs/04-pyweb-files.md) · [State & reactivity](docs/05-reactivity.md) · [Python in the browser](docs/07-browser-python.md) · [npm packages](docs/18-npm-packages.md) |
354
+ | Server | [Server functions & RPC](docs/06-server-functions.md) · [Pages & routing](docs/08-pages-routing-assets.md) · [Layouts & navigation](docs/19-layouts-navigation.md) · [Data](docs/09-data.md) · [Live data](docs/21-live-data.md) · [Building AI apps](docs/20-ai-apps.md) · [Auth](docs/10-auth.md) |
355
+ | Ship | [Testing](docs/11-testing.md) · [Deployment](docs/12-deployment.md) · [Security](docs/13-security.md) · [CLI](docs/14-cli.md) |
356
+ | Reference | [Recipe: wallets & web3](docs/22-recipe-web3.md) · [Toolkit & stability](docs/15-toolkit.md) · [Limitations & roadmap](docs/16-limitations-roadmap.md) · [Architecture](ARCHITECTURE.md) · [Changelog](CHANGELOG.md) |
357
+
358
+ The same docs are published at
359
+ **[maanavkrishna.github.io/PyWeb](https://maanavkrishna.github.io/PyWeb/)**,
360
+ with compiler output shown next to each example.
361
+
362
+ ## Is it for you?
363
+
364
+ **Good fit:** internal tools, admin panels, dashboards, CRUD apps, AI
365
+ features, small SaaS products and content sites with interactive parts,
366
+ built by people who'd rather stay in Python.
367
+
368
+ **Not a fit:** large client-heavy single-page apps built around a
369
+ JavaScript component framework (use React, Svelte or Vue), or running
370
+ scientific Python in the browser (use Pyodide or PyScript). See the
371
+ [introduction](docs/01-introduction.md) and the
372
+ [current limitations](docs/16-limitations-roadmap.md).
373
+
374
+ ## Status
375
+
376
+ PyWeb is in beta (0.x). The language, server API, RPC protocol and CLI
377
+ are documented and tested, and changes to them are announced in the
378
+ [changelog](CHANGELOG.md) (see [stability](docs/15-toolkit.md#stability)).
379
+ Upgrade with `pip install -U pyweb-stack`.
380
+
381
+ | Version | Highlights |
382
+ |---|---|
383
+ | 0.4 | npm packages without Node, layouts and client-side navigation, streaming server functions and `<Markdown>` for AI apps, live queries, page head tags, `.pyweb` error pages; 0.4.1: richer MCP tools |
384
+ | 0.3 | Hydration, live updates (SSE), multi-file apps, language server + VS Code extension, browser playground, faster rendering, screenshot/test MCP tools |
385
+ | 0.2 | MCP server for AI assistants, AI guide, project templates, `AGENTS.md`/`CLAUDE.md`, `llms.txt` |
386
+ | 0.1 | First public release: compiler, reactive runtime, server rendering, typed RPC, sessions, databases, CLI |
387
+
388
+ The test suite covers the parser, the Python→JavaScript translation
389
+ (differentially, against CPython), the reactive runtime, server
390
+ rendering, RPC, streaming, live queries, client-side navigation, every
391
+ example app in Chromium, the playground on Pyodide, and the
392
+ database/Redis layers against real Postgres, MySQL and Redis servers, on
393
+ Python 3.10–3.13.
394
+
395
+ ## Contributing
396
+
397
+ Issues and pull requests are welcome: see [CONTRIBUTING.md](CONTRIBUTING.md).
398
+ Security reports: [SECURITY.md](SECURITY.md).
399
+
400
+ Built by [MaanavKrishna](https://github.com/MaanavKrishna). MIT licensed.