fastui2 0.1.0__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.
fastui2-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,454 @@
1
+ Metadata-Version: 2.4
2
+ Name: fastui2
3
+ Version: 0.1.0
4
+ Summary: Build web UIs with Python decorators, compile to HTML, zero JavaScript required
5
+ Author-email: White NEFOR <n7for8572@gmail.com>
6
+ Maintainer-email: White NEFOR <n7for8572@gmail.com>
7
+ License: MIT
8
+ Project-URL: Homepage, https://github.com/ndugram/fastui2
9
+ Project-URL: Documentation, https://fastui.ndugram.dev
10
+ Project-URL: Repository, https://github.com/ndugram/fastui2
11
+ Project-URL: Issues, https://github.com/ndugram/fastui2/issues
12
+ Keywords: fastui,ui,web,html,decorators,python,pydantic,no-js
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Internet :: WWW/HTTP
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Topic :: Software Development :: User Interfaces
25
+ Classifier: Typing :: Typed
26
+ Requires-Python: >=3.10
27
+ Description-Content-Type: text/markdown
28
+ Requires-Dist: annotated-doc>=0.0.4
29
+ Requires-Dist: pydantic>=2.13.4
30
+ Provides-Extra: dev
31
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
32
+ Requires-Dist: ruff>=0.15.15; extra == "dev"
33
+ Requires-Dist: mypy>=1.15.0; extra == "dev"
34
+ Requires-Dist: mkdocs>=1.6.0; extra == "dev"
35
+ Requires-Dist: mkdocs-material>=9.5.0; extra == "dev"
36
+ Requires-Dist: pymdown-extensions>=10.21.3; extra == "dev"
37
+
38
+ <p align="center">
39
+ <img src="https://fastui.ndugram.dev/ru/latest/logo.png" style="background:white; padding:12px; border-radius:10px; width:350">
40
+ </p>
41
+ <p align="center">
42
+ <em>FastUI — build web UIs with Python decorators, compile to HTML, zero JavaScript required.</em>
43
+ </p>
44
+ <p align="center">
45
+ <a href="https://github.com/ndugram/fastui2/actions/workflows/tests.yml" target="_blank">
46
+ <img src="https://github.com/ndugram/fastui2/actions/workflows/tests.yml/badge.svg" alt="Tests">
47
+ </a>
48
+ <a href="https://pypi.org/project/fastui2" target="_blank">
49
+ <img src="https://img.shields.io/pypi/v/fastui2?color=%2334D058&label=pypi%20package" alt="Package version">
50
+ </a>
51
+ <a href="https://www.python.org/" target="_blank">
52
+ <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/ndugram/fastui/master/docs/endpoints/python.json" alt="Python">
53
+ </a>
54
+ <a href="https://pypi.org/project/fastui2" target="_blank">
55
+ <img src="https://img.shields.io/pypi/dm/fastui2?color=%2334D058&label=downloads" alt="Monthly downloads">
56
+ </a>
57
+ <a href="https://pepy.tech/projects/fastui2" target="_blank">
58
+ <img src="https://img.shields.io/pepy/dt/fastui2?color=%2334D058&label=total%20downloads" alt="Total downloads">
59
+ </a>
60
+ <a href="https://pydantic.dev" target="_blank">
61
+ <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/pydantic/pydantic/main/docs/badge/v2.json" alt="Pydantic v2">
62
+ </a>
63
+ </p>
64
+
65
+ ---
66
+
67
+ **Documentation**: <a href="https://fastui.ndugram.dev/ru/latest/" target="_blank">https://fastui.ndugram.dev/ru/latest/</a>
68
+
69
+ **Source Code**: <a href="https://github.com/ndugram/fastui2" target="_blank">https://github.com/ndugram/fastui2</a>
70
+
71
+ ---
72
+
73
+ FastUI is a modern **server-rendered UI library** for Python. It brings a decorator-based API — similar to FastAPI, but for building HTML pages — with Pydantic-validated components, URL routing, server-side actions, and a built-in Swagger UI.
74
+
75
+ Key features:
76
+
77
+ - **Fast** — components compile directly to HTML, no template engine overhead. Built-in hot reload for development.
78
+ - **Simple** — define pages as decorated Python functions, return component lists, no HTML templates.
79
+ - **Typed** — full type annotations throughout; all components are Pydantic-validated models with strict validation.
80
+ - **Zero JS** — everything compiles to plain HTML. Buttons with server actions use a lightweight POST mechanism.
81
+ - **Routed** — URL patterns with typed parameters (`/user/{id:int}`, `/post/{year:int}/{slug}`).
82
+ - **Interactive** — built-in Swagger UI via `/docs` to browse and test page routes in the browser.
83
+ - **Extensible** — custom CSS, external stylesheets, inline styles, component protocol for custom components.
84
+
85
+ ## Requirements
86
+
87
+ Python 3.10+
88
+
89
+ FastUI depends on:
90
+
91
+ - <a href="https://docs.pydantic.dev/" target="_blank"><code>pydantic</code></a> — component model validation and serialization.
92
+ - <a href="https://pypi.org/project/annotated-doc/" target="_blank"><code>annotated-doc</code></a> — parameter documentation via `Annotated[type, Doc("...")]`.
93
+
94
+ ## Installation
95
+
96
+ ```console
97
+ $ pip install fastui2
98
+
99
+ ---> 100%
100
+ ```
101
+
102
+ ## Example
103
+
104
+ ### Create it
105
+
106
+ Create a file `main.py`:
107
+
108
+ ```python
109
+ from fastui import App, ui
110
+
111
+ app = App()
112
+
113
+
114
+ @app.page("/")
115
+ def home():
116
+ return [
117
+ ui.heading("FastUI", level=1),
118
+ ui.text("Build UIs with Python. No JavaScript required."),
119
+ ui.button("About", on_click="/about"),
120
+ ]
121
+
122
+
123
+ @app.page("/about")
124
+ def about():
125
+ return [
126
+ ui.heading("About", level=1),
127
+ ui.text("FastUI compiles Pydantic components to HTML."),
128
+ ui.link("Back", url="/"),
129
+ ]
130
+
131
+
132
+ if __name__ == "__main__":
133
+ app.run()
134
+ ```
135
+
136
+ ### Run it
137
+
138
+ ```console
139
+ $ python main.py
140
+ ```
141
+
142
+ ### Check it
143
+
144
+ You will see output like:
145
+
146
+ ```
147
+ ╔════════════════════════════════════════════╗
148
+ ║ FastUI Dev Server ║
149
+ ╠════════════════════════════════════════════╣
150
+ ║ ║
151
+ ║ → http://127.0.0.1:8000 ║
152
+ ║ ║
153
+ ║ ♻ Hot reload ║
154
+ ║ ║
155
+ ║ 📖 Docs http://127.0.0.1:8000/docs ║
156
+ ║ ║
157
+ ║ Routes: ║
158
+ ║ • / ║
159
+ ║ • /about ║
160
+ ║ ║
161
+ ╚════════════════════════════════════════════╝
162
+ ```
163
+
164
+ Open `http://127.0.0.1:8000` in your browser.
165
+
166
+ ### Interactive API docs
167
+
168
+ Now go to <a href="http://127.0.0.1:8000/docs" target="_blank">http://127.0.0.1:8000/docs</a>.
169
+
170
+ You will see the automatic interactive API documentation with all registered routes:
171
+
172
+ <img src="docs/photo/swagger_ui_home.png">
173
+
174
+ Each route shows its URL pattern, summary, parameters, and response schema:
175
+
176
+ <img src="docs/photo/swagger_ui_check_web.png">
177
+
178
+ Routes with path parameters (`{id:int}`, `{slug}`) have input fields for testing:
179
+
180
+ <img src="docs/photo/swagger_ui_check_execute.png">
181
+
182
+ ### Upgrade the example
183
+
184
+ Now modify `main.py` to get more out of FastUI. Each upgrade below builds on the previous one.
185
+
186
+ <details markdown="1">
187
+ <summary>With typed URL parameters...</summary>
188
+
189
+ Add a route with an integer parameter:
190
+
191
+ ```python
192
+ @app.page("/user/{id:int}", title="Profile")
193
+ def user_profile(id: int):
194
+ return [
195
+ ui.heading(f"User #{id}", level=1),
196
+ ui.text(f"Profile page for user {id}."),
197
+ ui.link("Back", url="/"),
198
+ ]
199
+ ```
200
+
201
+ Visit `http://127.0.0.1:8000/user/42`. The `id` parameter is automatically converted to `int`.
202
+
203
+ </details>
204
+
205
+ <details markdown="1">
206
+ <summary>With server actions (POST handlers)...</summary>
207
+
208
+ Buttons can call Python functions on the server via POST:
209
+
210
+ ```python
211
+ counter = 0
212
+
213
+
214
+ def increment() -> list:
215
+ global counter
216
+ counter += 1
217
+ return [
218
+ ui.heading(f"Count: {counter}", level=1),
219
+ ui.button("+1", on_click=increment),
220
+ ui.link("Back", url="/counter"),
221
+ ]
222
+
223
+
224
+ @app.page("/counter")
225
+ def counter_page():
226
+ return [
227
+ ui.heading("Counter", level=1),
228
+ ui.text(f"Value: {counter}"),
229
+ ui.button("+1", on_click=increment),
230
+ ]
231
+ ```
232
+
233
+ When `on_click` receives a callable, the framework registers it as a POST endpoint and
234
+ replaces it with the action URL before rendering.
235
+
236
+ </details>
237
+
238
+ <details markdown="1">
239
+ <summary>With custom CSS...</summary>
240
+
241
+ Pass custom CSS to the `App` constructor:
242
+
243
+ ```python
244
+ CUSTOM = """
245
+ body { background: #1a1a2e; color: #e0e0e0; }
246
+ h1 { color: #e94560; }
247
+ button { background: #e94560; color: #fff; border: none; }
248
+ """
249
+
250
+ app = App(css=CUSTOM)
251
+ ```
252
+
253
+ Or use external stylesheets:
254
+
255
+ ```python
256
+ app.stylesheets = [
257
+ "https://cdn.jsdelivr.net/npm/bootstrap@5.3/dist/css/bootstrap.min.css",
258
+ ]
259
+ ```
260
+
261
+ </details>
262
+
263
+ <details markdown="1">
264
+ <summary>With OpenAPI tags...</summary>
265
+
266
+ Group routes in the Swagger UI with tags:
267
+
268
+ ```python
269
+ @app.page("/users", title="Users", tags=["users"])
270
+ def users():
271
+ return [ui.heading("Users", level=1)]
272
+
273
+ @app.page("/items", title="Items", tags=["items"])
274
+ def items():
275
+ return [ui.heading("Items", level=1)]
276
+ ```
277
+
278
+ Tags appear as a filter in the Swagger UI header.
279
+
280
+ </details>
281
+
282
+ <details markdown="1">
283
+ <summary>With a multi-page layout...</summary>
284
+
285
+ Share navigation across pages with a helper function:
286
+
287
+ ```python
288
+ def nav() -> ui.page:
289
+ return ui.page([
290
+ ui.link("Home", url="/", style="margin-right: 1rem;"),
291
+ ui.link("Blog", url="/blog", style="margin-right: 1rem;"),
292
+ ui.link("About", url="/about"),
293
+ ], style="padding: 1rem; background: #f0f0f0; border-radius: 8px; margin-bottom: 1rem;")
294
+
295
+ @app.page("/")
296
+ def home():
297
+ return [nav(), ui.heading("Home", level=1), ui.text("Welcome!")]
298
+
299
+ @app.page("/about")
300
+ def about():
301
+ return [nav(), ui.heading("About", level=1), ui.text("FastUI details.")]
302
+ ```
303
+
304
+ </details>
305
+
306
+ ## Components
307
+
308
+ All built-in components are available through the `ui` builder:
309
+
310
+ | Component | Builder | HTML |
311
+ |---|---|---|
312
+ | Heading | `ui.heading("text", level=1)` | `<h1>text</h1>` |
313
+ | Text | `ui.text("content")` | `<p>content</p>` |
314
+ | Button | `ui.button("label", on_click=...)` | `<button>label</button>` |
315
+ | Input | `ui.input(label="Name")` | `<label>Name<input></label>` |
316
+ | Link | `ui.link("text", url="/")` | `<a href="/">text</a>` |
317
+ | Code | `ui.code("code")` | `<pre><code>code</code></pre>` |
318
+ | Divider | `ui.divider()` | `<hr>` |
319
+ | Page | `ui.page([...])` | `<div>...</div>` |
320
+
321
+ Every component accepts optional styling:
322
+
323
+ ```python
324
+ ui.heading("Styled", level=2, style="color: red;")
325
+ ui.button("Big", class_name="btn-lg", style="padding: 1rem;")
326
+ ui.text("Centered", style="text-align: center;")
327
+ ```
328
+
329
+ ## Routing
330
+
331
+ Routes map URL patterns to handler functions. Patterns support typed parameters:
332
+
333
+ | Pattern | Example URL | Handler receives |
334
+ |---|---|---|
335
+ | `/` | `/` | — |
336
+ | `/about` | `/about` | — |
337
+ | `/user/{id:int}` | `/user/42` | `id=42` (int) |
338
+ | `/hello/{name}` | `/hello/world` | `name='world'` (str) |
339
+ | `/post/{year:int}/{slug}` | `/post/2025/hello` | `year=2025, slug='hello'` |
340
+
341
+ Routes are registered in order; the first match wins.
342
+
343
+ ## Server actions
344
+
345
+ Buttons can call server-side Python functions via POST:
346
+
347
+ ```python
348
+ def handle_click() -> list:
349
+ return [
350
+ ui.heading("Clicked!", level=2, style="color: green;"),
351
+ ui.link("Back", url="/"),
352
+ ]
353
+
354
+ @app.page("/")
355
+ def index():
356
+ return [
357
+ ui.button("Click me", on_click=handle_click),
358
+ ]
359
+ ```
360
+
361
+ The framework automatically:
362
+
363
+ 1. Registers the callable as a POST endpoint at `/_ui/action/<id>`
364
+ 2. Replaces the callable with the action URL in the rendered HTML
365
+ 3. On click, the browser POSTs to the action URL
366
+ 4. The handler runs and returns new components rendered as HTML
367
+
368
+ ## OpenAPI documentation
369
+
370
+ FastUI auto-generates OpenAPI 3.0 schema for all routes. Available at `/docs` (Swagger UI)
371
+ and `/openapi.json` by default.
372
+
373
+ ```python
374
+ app = App(
375
+ title="My API",
376
+ version="2.0.0",
377
+ description="API description in **Markdown**.",
378
+ docs_url="/api-docs",
379
+ openapi_url="/api-schema.json",
380
+ )
381
+ ```
382
+
383
+ Disable docs:
384
+
385
+ ```python
386
+ app = App(docs=False)
387
+ ```
388
+
389
+ ## Hot reload
390
+
391
+ Enable auto-refresh on file changes:
392
+
393
+ ```python
394
+ app.run(hot_reload=True)
395
+ ```
396
+
397
+ The server polls `.py` files in the current directory and the `fastui` package directory.
398
+ On change, the browser refreshes automatically.
399
+
400
+ ## Examples
401
+
402
+ See the [examples](examples/) directory for 20 complete, runnable programs:
403
+
404
+ | # | Example | What it shows |
405
+ |---|---|---|
406
+ | 1 | [hello_world](examples/01_hello_world.py) | Minimal app — one page, one heading |
407
+ | 2 | [all_components](examples/02_all_components.py) | Every built-in component type |
408
+ | 3 | [route_params](examples/03_route_params.py) | URL patterns with typed parameters |
409
+ | 4 | [server_actions](examples/04_server_actions.py) | POST callback handlers |
410
+ | 5 | [custom_css](examples/05_custom_css.py) | Dark theme with custom CSS |
411
+ | 6 | [forms](examples/06_forms.py) | Input fields and form layout |
412
+ | 7 | [navigation](examples/07_navigation.py) | Multi-page navigation with links |
413
+ | 8 | [docs_config](examples/08_docs_config.py) | Custom OpenAPI docs metadata |
414
+ | 9 | [layout_page](examples/09_layout_page.py) | Page component for grouping |
415
+ | 10 | [counter](examples/10_counter.py) | Interactive counter with actions |
416
+ | 11 | [todo](examples/11_todo.py) | Simple todo application |
417
+ | 12 | [hot_reload](examples/12_hot_reload.py) | Hot reload demo |
418
+ | 13 | [multi_page](examples/13_multi_page.py) | Shared navigation layout |
419
+ | 14 | [no_docs](examples/14_no_docs.py) | Running without docs |
420
+ | 15 | [external_stylesheets](examples/15_external_stylesheets.py) | Bootstrap integration |
421
+ | 16 | [single_component](examples/16_single_component.py) | Returning single vs list |
422
+ | 17 | [advanced_routing](examples/17_advanced_routing.py) | Complex multi-param routes |
423
+ | 18 | [inline_styles](examples/18_inline_styles.py) | All style combinations |
424
+ | 19 | [minimal](examples/19_minimal.py) | Absolute minimal app (7 lines) |
425
+ | 20 | [dynamic_routes](examples/20_dynamic_routes.py) | Dynamically generated routes |
426
+
427
+ ## FAQ
428
+
429
+ - **Why would I use FastUI instead of Flask + Jinja2?**
430
+ FastUI eliminates the template layer — you write UIs entirely in Python without HTML files.
431
+ It's ideal for small to medium apps where the overhead of a template engine isn't justified.
432
+
433
+ - **Why would I use FastUI instead of Streamlit?**
434
+ FastUI gives you explicit control over routing, URL parameters, and page structure.
435
+ Streamlit is script-based and re-runs everything on every interaction; FastUI uses
436
+ traditional request-response with proper URL routing.
437
+
438
+ - **Does FastUI support async handlers?**
439
+ Not yet. Handlers are synchronous. Async support is planned.
440
+
441
+ - **Can I use FastUI with an existing HTTP server?**
442
+ The `App` class runs its own dev server. For production, you'd wrap it in ASGI/WSGI —
443
+ this is on the roadmap.
444
+
445
+ - **Does FastUI support WebSockets?**
446
+ Not currently. Server-sent events and WebSocket support may be added later.
447
+
448
+ - **Can I write my own components?**
449
+ Yes. Any object with a `to_html()` method satisfies the `Component` protocol.
450
+ Pydantic models with `to_html()` work seamlessly.
451
+
452
+ - **Is FastUI production-ready?**
453
+ FastUI is in early development (v0.1.0). The API may change. It's suitable for
454
+ internal tools and prototypes but not yet for customer-facing production apps.