frontage 0.16.1__py3-none-win_amd64.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 (142) hide show
  1. frontage/__init__.py +38 -0
  2. frontage/__init__.pyi +85 -0
  3. frontage/__main__.py +8 -0
  4. frontage/_bin/fpy.exe +0 -0
  5. frontage/_exports.py +87 -0
  6. frontage/_runtime/boot.js +127 -0
  7. frontage/_runtime/frontage-compiler.wasm +0 -0
  8. frontage/_runtime/frontage.wasm +0 -0
  9. frontage/_runtime/glue.js +464 -0
  10. frontage/_runtime/island.js +100 -0
  11. frontage/_stdlib/README.md +23 -0
  12. frontage/_stdlib/contextlib.py +266 -0
  13. frontage/a11y.py +69 -0
  14. frontage/aio.py +366 -0
  15. frontage/chart/README.md +201 -0
  16. frontage/chart/__init__.py +51 -0
  17. frontage/chart/_browser/canvas.js +1633 -0
  18. frontage/chart/_browser/index.css +12 -0
  19. frontage/chart/_browser/index.js +92 -0
  20. frontage/chart/canvas.py +236 -0
  21. frontage/chart/expr.py +338 -0
  22. frontage/chart/grammar.py +1845 -0
  23. frontage/chart/pen.py +437 -0
  24. frontage/chart/plot.py +78 -0
  25. frontage/chart/stats.py +101 -0
  26. frontage/chart/timeunit.py +153 -0
  27. frontage/chart/transform.py +107 -0
  28. frontage/chart/vega.py +61 -0
  29. frontage/chat/README.md +86 -0
  30. frontage/chat/__init__.py +250 -0
  31. frontage/chat/_browser/index.css +55 -0
  32. frontage/chat/_browser/index.js +47 -0
  33. frontage/chat/_server.py +130 -0
  34. frontage/chat/server.py +10 -0
  35. frontage/chat/style.py +63 -0
  36. frontage/chunks.py +180 -0
  37. frontage/cli/__init__.py +85 -0
  38. frontage/cli/_cache.py +14 -0
  39. frontage/cli/build.py +454 -0
  40. frontage/cli/check.py +74 -0
  41. frontage/cli/frontage_rt.py +235 -0
  42. frontage/cli/graph.py +292 -0
  43. frontage/cli/prerender.py +660 -0
  44. frontage/cli/serve.py +838 -0
  45. frontage/cli/site.py +721 -0
  46. frontage/cli/tailwind.py +89 -0
  47. frontage/content/__init__.py +442 -0
  48. frontage/debug.py +21 -0
  49. frontage/dev.py +219 -0
  50. frontage/devtools.py +114 -0
  51. frontage/dom.py +736 -0
  52. frontage/dsp/README.md +45 -0
  53. frontage/dsp/__init__.py +101 -0
  54. frontage/dsp/_browser/dsp.wasm +0 -0
  55. frontage/dsp/_browser/index.js +89 -0
  56. frontage/errors.py +37 -0
  57. frontage/flow.py +425 -0
  58. frontage/head.py +191 -0
  59. frontage/i18n.py +78 -0
  60. frontage/island.py +271 -0
  61. frontage/layout/README.md +33 -0
  62. frontage/layout/__init__.py +125 -0
  63. frontage/layout/_browser/index.css +48 -0
  64. frontage/layout/_browser/index.js +4 -0
  65. frontage/layout/style.py +56 -0
  66. frontage/lsp/__init__.py +28 -0
  67. frontage/lsp/data.py +424 -0
  68. frontage/lsp/documents.py +143 -0
  69. frontage/lsp/features.py +360 -0
  70. frontage/lsp/protocol.py +125 -0
  71. frontage/lsp/rules.py +320 -0
  72. frontage/lsp/scanner.py +545 -0
  73. frontage/lsp/server.py +240 -0
  74. frontage/map/README.md +93 -0
  75. frontage/map/__init__.py +18 -0
  76. frontage/map/_browser/index.css +667 -0
  77. frontage/map/_browser/index.js +108 -0
  78. frontage/map/_browser/leaflet.js +17 -0
  79. frontage/map/map.py +71 -0
  80. frontage/reactive.py +1427 -0
  81. frontage/remote/README.md +187 -0
  82. frontage/remote/__init__.py +9 -0
  83. frontage/remote/_browser/index.js +40 -0
  84. frontage/remote/_server.py +720 -0
  85. frontage/remote/client.py +296 -0
  86. frontage/remote/server.py +15 -0
  87. frontage/renderer.py +521 -0
  88. frontage/router.py +968 -0
  89. frontage/runtime.py +124 -0
  90. frontage/schema/README.md +146 -0
  91. frontage/schema/__init__.py +912 -0
  92. frontage/schema/_browser/index.css +3 -0
  93. frontage/schema/_browser/index.js +5 -0
  94. frontage/schema/_compile.py +106 -0
  95. frontage/schema/form.py +152 -0
  96. frontage/schema/jsonschema.py +223 -0
  97. frontage/state.py +124 -0
  98. frontage/state.pyi +22 -0
  99. frontage/store.py +297 -0
  100. frontage/supabase/README.md +155 -0
  101. frontage/supabase/__init__.py +27 -0
  102. frontage/supabase/_browser/index.js +7 -0
  103. frontage/supabase/client.py +254 -0
  104. frontage/supabase/query.py +241 -0
  105. frontage/supabase/realtime.py +187 -0
  106. frontage/table/README.md +57 -0
  107. frontage/table/__init__.py +234 -0
  108. frontage/table/_browser/index.css +40 -0
  109. frontage/table/_browser/index.js +4 -0
  110. frontage/table/style.py +44 -0
  111. frontage/template.py +225 -0
  112. frontage/testing.py +528 -0
  113. frontage/version.py +3 -0
  114. frontage/view.py +1063 -0
  115. frontage/widgets.py +139 -0
  116. frontage-0.16.1.dist-info/METADATA +255 -0
  117. frontage-0.16.1.dist-info/RECORD +142 -0
  118. frontage-0.16.1.dist-info/WHEEL +4 -0
  119. frontage-0.16.1.dist-info/entry_points.txt +3 -0
  120. frontage-0.16.1.dist-info/licenses/LICENSE +202 -0
  121. frontage-0.16.1.dist-info/licenses/NOTICE +11 -0
  122. frontage_server/__init__.py +1459 -0
  123. frontage_server/_binary.py +86 -0
  124. frontage_server/_cpython/__init__.py +333 -0
  125. frontage_server/_cpython/__main__.py +5 -0
  126. frontage_server/_cpython/host.py +106 -0
  127. frontage_server/_cpython/http.py +66 -0
  128. frontage_server/_cpython/turso.py +83 -0
  129. frontage_server/_cpython/upload.py +21 -0
  130. frontage_server/_scope.py +84 -0
  131. frontage_server/client.py +265 -0
  132. frontage_server/cors.py +62 -0
  133. frontage_server/db.py +122 -0
  134. frontage_server/depends.py +92 -0
  135. frontage_server/docs.py +196 -0
  136. frontage_server/openapi.py +232 -0
  137. frontage_server/pages.py +141 -0
  138. frontage_server/routing.py +276 -0
  139. frontage_server/session.py +186 -0
  140. frontage_server/streaming.py +161 -0
  141. frontage_server/testing.py +185 -0
  142. frontage_server/upload.py +160 -0
frontage/__init__.py ADDED
@@ -0,0 +1,38 @@
1
+ """Frontage: a fine-grained reactive UI framework for Python in the browser.
2
+
3
+ M5 of the rewrite (see project/design/architecture.md): the reactive core, the store, reactive views with the
4
+ insert rules, templates (`h` and `html(t"…")`), control flow and boundaries, Resource and
5
+ Action, the router, widgets, State, delegated events, and the DOM renderer.
6
+ """
7
+
8
+ import sys
9
+
10
+ from ._exports import EXPORTS
11
+ from .version import __version__
12
+
13
+ __all__ = sorted(EXPORTS) + ["__version__"]
14
+
15
+
16
+ def __getattr__(name):
17
+ """`from frontage import Signal` loads `frontage.reactive` and nothing else.
18
+
19
+ The package used to import every module up front, so a counter shipped the router, the
20
+ store and the template parser. Resolving names on first use (PEP 562, which MicroPython
21
+ supports) is what lets `frontage build` pack only the modules a page reaches — the table
22
+ in `_exports.py` is what both this function and the build read.
23
+ """
24
+ module = EXPORTS.get(name)
25
+ if module is None:
26
+ # `from . import reactive` inside the package: CPython resolves a submodule itself when
27
+ # the attribute is missing, MicroPython asks here first. A name that is neither a
28
+ # public name nor a module is the usual AttributeError.
29
+ try:
30
+ __import__("frontage." + name)
31
+ except ImportError:
32
+ raise AttributeError("module 'frontage' has no attribute '%s'" % name) from None
33
+ return sys.modules["frontage." + name]
34
+ qualified = "frontage." + module
35
+ __import__(qualified)
36
+ value = getattr(sys.modules[qualified], name)
37
+ globals()[name] = value # resolved once; the next access is a plain lookup
38
+ return value
frontage/__init__.pyi ADDED
@@ -0,0 +1,85 @@
1
+ # Generated from _exports.py by `tools/exports.py`: the static view of the lazy package,
2
+ # for editors and ty.
3
+
4
+ from .aio import Action as Action
5
+ from .aio import Resource as Resource
6
+ from .aio import interval as interval
7
+ from .aio import poll as poll
8
+ from .errors import FrontageError as FrontageError
9
+ from .errors import NotReady as NotReady
10
+ from .errors import RenderError as RenderError
11
+ from .errors import format_exception as format_exception
12
+ from .flow import Dynamic as Dynamic
13
+ from .flow import Errored as Errored
14
+ from .flow import For as For
15
+ from .flow import Loading as Loading
16
+ from .flow import Match as Match
17
+ from .flow import Portal as Portal
18
+ from .flow import Show as Show
19
+ from .flow import Switch as Switch
20
+ from .head import Meta as Meta
21
+ from .head import Title as Title
22
+ from .island import island as island
23
+ from .reactive import Context as Context
24
+ from .reactive import Effect as Effect
25
+ from .reactive import Memo as Memo
26
+ from .reactive import Optimistic as Optimistic
27
+ from .reactive import Owner as Owner
28
+ from .reactive import RenderEffect as RenderEffect
29
+ from .reactive import Signal as Signal
30
+ from .reactive import Transition as Transition
31
+ from .reactive import batch as batch
32
+ from .reactive import get_owner as get_owner
33
+ from .reactive import is_pending as is_pending
34
+ from .reactive import latest as latest
35
+ from .reactive import on as on
36
+ from .reactive import on_cleanup as on_cleanup
37
+ from .reactive import on_mount as on_mount
38
+ from .reactive import provide as provide
39
+ from .reactive import refresh as refresh
40
+ from .reactive import run_with_owner as run_with_owner
41
+ from .reactive import selector as selector
42
+ from .reactive import spawn as spawn
43
+ from .reactive import transition as transition
44
+ from .reactive import tree as tree
45
+ from .reactive import untrack as untrack
46
+ from .reactive import use as use
47
+ from .reactive import use_transition as use_transition
48
+ from .renderer import HtmlRenderer as HtmlRenderer
49
+ from .renderer import RecordingRenderer as RecordingRenderer
50
+ from .renderer import Renderer as Renderer
51
+ from .router import A as A
52
+ from .router import ActionForm as ActionForm
53
+ from .router import Navigate as Navigate
54
+ from .router import Redirect as Redirect
55
+ from .router import Route as Route
56
+ from .router import Router as Router
57
+ from .router import use_location as use_location
58
+ from .router import use_navigate as use_navigate
59
+ from .router import use_params as use_params
60
+ from .router import use_query as use_query
61
+ from .runtime import in_browser as in_browser
62
+ from .runtime import platform as platform
63
+ from .state import State as State
64
+ from .state import computed as computed
65
+ from .state import field as field
66
+ from .store import Store as Store
67
+ from .store import reconcile as reconcile
68
+ from .store import snapshot as snapshot
69
+ from .template import html as html
70
+ from .version import __version__ as __version__
71
+ from .view import Element as Element
72
+ from .view import Mounted as Mounted
73
+ from .view import NodeRef as NodeRef
74
+ from .view import Text as Text
75
+ from .view import build as build
76
+ from .view import comment as comment
77
+ from .view import component as component
78
+ from .view import emit as emit
79
+ from .view import h as h
80
+ from .view import mount as mount
81
+ from .view import render_to_string as render_to_string
82
+ from .view import text as text
83
+ from .view import unique_id as unique_id
84
+
85
+ __all__: list[str]
frontage/__main__.py ADDED
@@ -0,0 +1,8 @@
1
+ """`python -m frontage`: the command line (build, prerender, serve, check, tailwind). Never imported
2
+ in the browser."""
3
+
4
+ import sys
5
+
6
+ from frontage.cli import main
7
+
8
+ sys.exit(main())
frontage/_bin/fpy.exe ADDED
Binary file
frontage/_exports.py ADDED
@@ -0,0 +1,87 @@
1
+ # The public names of `frontage`, and the module each lives in. One table, two readers:
2
+ # `frontage/__init__.py` resolves `from frontage import Signal` through it on first use
3
+ # (PEP 562, so a page loads only the modules it reaches), and `frontage build`'s import
4
+ # walk attributes the same name to the same module without importing anything. Keep it
5
+ # sorted by module, then name; `__init__.pyi` is generated from it by `mk exports`.
6
+
7
+ EXPORTS = {
8
+ "Action": "aio",
9
+ "Resource": "aio",
10
+ "interval": "aio",
11
+ "poll": "aio",
12
+ "FrontageError": "errors",
13
+ "NotReady": "errors",
14
+ "RenderError": "errors",
15
+ "format_exception": "errors",
16
+ "Dynamic": "flow",
17
+ "Errored": "flow",
18
+ "For": "flow",
19
+ "Loading": "flow",
20
+ "Match": "flow",
21
+ "Portal": "flow",
22
+ "Show": "flow",
23
+ "Switch": "flow",
24
+ "Meta": "head",
25
+ "Title": "head",
26
+ "island": "island",
27
+ "Context": "reactive",
28
+ "Effect": "reactive",
29
+ "Memo": "reactive",
30
+ "Optimistic": "reactive",
31
+ "Owner": "reactive",
32
+ "RenderEffect": "reactive",
33
+ "Signal": "reactive",
34
+ "Transition": "reactive",
35
+ "batch": "reactive",
36
+ "get_owner": "reactive",
37
+ "is_pending": "reactive",
38
+ "latest": "reactive",
39
+ "on": "reactive",
40
+ "on_cleanup": "reactive",
41
+ "on_mount": "reactive",
42
+ "provide": "reactive",
43
+ "refresh": "reactive",
44
+ "run_with_owner": "reactive",
45
+ "selector": "reactive",
46
+ "spawn": "reactive",
47
+ "transition": "reactive",
48
+ "tree": "reactive",
49
+ "untrack": "reactive",
50
+ "use": "reactive",
51
+ "use_transition": "reactive",
52
+ "HtmlRenderer": "renderer",
53
+ "RecordingRenderer": "renderer",
54
+ "Renderer": "renderer",
55
+ "A": "router",
56
+ "ActionForm": "router",
57
+ "Navigate": "router",
58
+ "Redirect": "router",
59
+ "Route": "router",
60
+ "Router": "router",
61
+ "use_location": "router",
62
+ "use_navigate": "router",
63
+ "use_params": "router",
64
+ "use_query": "router",
65
+ "in_browser": "runtime",
66
+ "platform": "runtime",
67
+ "State": "state",
68
+ "computed": "state",
69
+ "field": "state",
70
+ "Store": "store",
71
+ "reconcile": "store",
72
+ "snapshot": "store",
73
+ "html": "template",
74
+ "Element": "view",
75
+ "Mounted": "view",
76
+ "NodeRef": "view",
77
+ "Text": "view",
78
+ "build": "view",
79
+ "comment": "view",
80
+ "component": "view",
81
+ "emit": "view",
82
+ "h": "view",
83
+ "mount": "view",
84
+ "render_to_string": "view",
85
+ "text": "view",
86
+ "unique_id": "view",
87
+ }
@@ -0,0 +1,127 @@
1
+ // Boot a page on frontage's runtime: the wasm, the compiled modules named in
2
+ // `manifest.json`, then the entry as `__main__`. The page declares what to run:
3
+ //
4
+ // <script type="module" src="./_frontage/boot.js" data-fr-boot data-fr-entry="counter"></script>
5
+ //
6
+ // `data-fr-compiler` on the tag loads `frontage-compiler.wasm` instead, the same runtime with
7
+ // the compiler in it, for a page that runs a program someone types (the playground).
8
+ // Everything resolves from `import.meta.url`, so a page at any depth finds its runtime.
9
+
10
+ import { load } from "./glue.js";
11
+
12
+ const asset = (name) => new URL(name, import.meta.url).href;
13
+ let rtAssets = "";
14
+
15
+ async function bytes(url) {
16
+ const response = await fetch(url);
17
+ if (!response.ok) throw new Error(`frontage: ${response.status} fetching ${url}`);
18
+ return new Uint8Array(await response.arrayBuffer());
19
+ }
20
+
21
+ const console_io = {
22
+ stdout: (s) => console.log(s.replace(/\n$/, "")),
23
+ stderr: (s) => console.error(s.replace(/\n$/, "")),
24
+ };
25
+
26
+ /**
27
+ * The runtime with the compiler in it and no application: for a page that holds its program
28
+ * in a URL fragment or a text box (the runner, the playground) and has nothing to fetch.
29
+ * `rt.runSource(code)` runs it as `__main__`. Deliberately touches nothing in the document.
30
+ */
31
+ export async function startRuntime() {
32
+ const [rt, framework] = await Promise.all([
33
+ load(asset("frontage-compiler.wasm"), console_io),
34
+ fetch(asset("framework.json")).then((r) => r.json()),
35
+ ]);
36
+ await addModules(rt, framework.modules);
37
+ return rt;
38
+ }
39
+
40
+ // A built app's manifest names each module's content-hashed file; the dev server's does not.
41
+ let files = {};
42
+ const fileOf = (name) => files[name] || `${name}.fbc`;
43
+
44
+ async function addModules(rt, names) {
45
+ const modules = await Promise.all(names.map(async (name) => [name, await bytes(asset(fileOf(name)))]));
46
+ for (const [name, fbc] of modules) rt.addModule(name, fbc);
47
+ }
48
+
49
+ /**
50
+ * The runtime, this page's modules, and the JavaScript libraries the tag declares. `run`
51
+ * picks, from the manifest, the file whose bytecode becomes `__main__` once everything is
52
+ * in: an app's entry, or — for a page of islands, which has no entry to run —
53
+ * `frontage.island`.
54
+ */
55
+ async function start(tag, run) {
56
+ // A page that runs a typed program (`data-fr-compiler`) gets the whole framework, since
57
+ // the program may import any of it; a built app gets its entry's import closure.
58
+ const compiler = tag !== null && tag.dataset.frCompiler !== undefined;
59
+ const [manifest, framework] = await Promise.all([
60
+ fetch(asset("manifest.json")).then((r) => r.json()),
61
+ compiler ? fetch(asset("framework.json")).then((r) => r.json()) : { modules: [] },
62
+ ]);
63
+ files = manifest.files || {};
64
+ // What a chunk fetch needs later: where these files live, and which modules are in each.
65
+ rtAssets = asset("");
66
+ const rt = await load(asset(compiler ? "frontage-compiler.wasm" : manifest.wasm || "frontage.wasm"), console_io);
67
+ const names = [...new Set([...framework.modules, ...manifest.modules])];
68
+ await addModules(rt, names);
69
+ // JavaScript modules the app asked for (`data-fr-js="name=./lib.js, ./other.js"`): the
70
+ // glue around a C or Rust library compiled to WebAssembly. Named ones become Python
71
+ // modules. Resolved from `../` of this file, the app's own directory in every layout.
72
+ const appRoot = new URL("../", import.meta.url);
73
+ for (const item of ((tag && tag.dataset.frJs) || "").split(",")) {
74
+ const spec = item.trim();
75
+ if (!spec) continue;
76
+ const eq = spec.indexOf("=");
77
+ const name = eq > 0 ? spec.slice(0, eq).trim() : "";
78
+ const specifier = eq > 0 ? spec.slice(eq + 1).trim() : spec;
79
+ const namespace = await import(new URL(specifier, appRoot).href);
80
+ if (name) rt.registerJsModule(name, namespace);
81
+ }
82
+ const main = await bytes(asset(run(manifest)));
83
+ rt.assetBase = rtAssets;
84
+ rt.manifest = manifest;
85
+ window.frontage = rt;
86
+ const code = rt.run(main);
87
+ if (code === 1) console.error("frontage: the entry raised; see above");
88
+ return rt;
89
+ }
90
+
91
+ /**
92
+ * A static page whose islands have started asking for a runtime (`island.js`). There is no
93
+ * entry to run — the page's HTML was written at build time — so what runs is
94
+ * `frontage.island`, which mounts each queued wrapper over the markup already on screen.
95
+ * Called once per page, however many islands there are.
96
+ */
97
+ export async function startIslands() {
98
+ const tag = document.querySelector("script[data-fr-islands]");
99
+ return start(tag, () => fileOf("frontage.island"));
100
+ }
101
+
102
+ async function boot() {
103
+ const tag = document.querySelector("script[data-fr-boot]");
104
+ if (!tag) {
105
+ // Not an error: a page may import this module for `startRuntime` or `startIslands` alone.
106
+ if (!document.querySelector("script[data-fr-islands]")) {
107
+ console.warn("frontage: no <script data-fr-boot> on the page, so nothing was mounted");
108
+ }
109
+ return null;
110
+ }
111
+ const entry = tag.dataset.frEntry || "app";
112
+ // `manifest.entry` is the built app's content-hashed entry file; the dev server's manifest
113
+ // has none, and the module is asked for by its plain name.
114
+ return start(tag, (manifest) => manifest.entry || `${entry}.fbc`);
115
+ }
116
+
117
+ const parsed =
118
+ document.readyState === "loading"
119
+ ? new Promise((done) => document.addEventListener("DOMContentLoaded", done, { once: true }))
120
+ : Promise.resolve();
121
+
122
+ export const ready = parsed.then(boot);
123
+ ready.catch((error) => {
124
+ setTimeout(() => {
125
+ throw error;
126
+ });
127
+ });
Binary file
Binary file