pyon-py 0.1.0__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 (59) hide show
  1. pyon/__init__.py +12 -0
  2. pyon/browser/__init__.py +4 -0
  3. pyon/browser/_protocol/__init__.py +46 -0
  4. pyon/browser/_protocol/dom.py +484 -0
  5. pyon/browser/_protocol/ffi.py +29 -0
  6. pyon/browser/_protocol/http.py +52 -0
  7. pyon/browser/impl/__init__.py +52 -0
  8. pyon/browser/impl/pyodide_impl/__init__.py +5 -0
  9. pyon/browser/impl/pyodide_impl/ffi.py +14 -0
  10. pyon/browser/impl/pyodide_impl/http.py +16 -0
  11. pyon/browser/impl/pyodide_impl/js.py +14 -0
  12. pyon/cli/__init__.py +0 -0
  13. pyon/cli/add.py +134 -0
  14. pyon/cli/dev.py +23 -0
  15. pyon/cli/download.py +136 -0
  16. pyon/cli/init.py +208 -0
  17. pyon/cli/main.py +21 -0
  18. pyon/cli/remove.py +71 -0
  19. pyon/cli/utils/lock_utils.py +36 -0
  20. pyon/cli/utils/toml_utils.py +52 -0
  21. pyon/cli/utils/wasm_check.py +62 -0
  22. pyon/core/__init__.py +45 -0
  23. pyon/core/app.py +872 -0
  24. pyon/core/bus.py +33 -0
  25. pyon/core/component.py +537 -0
  26. pyon/core/css.py +14 -0
  27. pyon/core/differ.py +440 -0
  28. pyon/core/dom.py +280 -0
  29. pyon/core/events.py +520 -0
  30. pyon/core/template.py +247 -0
  31. pyon/core/utils.py +53 -0
  32. pyon/core/vnode.py +141 -0
  33. pyon/dev_server/__init__.py +0 -0
  34. pyon/dev_server/server.py +645 -0
  35. pyon/dom/__init__.py +6 -0
  36. pyon/dom/css.py +63 -0
  37. pyon/dom/patch.py +184 -0
  38. pyon/dom/props.py +65 -0
  39. pyon/dom/render.py +105 -0
  40. pyon/dom/scheduler.py +25 -0
  41. pyon/env/__init__.py +3 -0
  42. pyon/env/env.py +32 -0
  43. pyon/http/__init__.py +6 -0
  44. pyon/http/client.py +54 -0
  45. pyon/http/exceptions.py +9 -0
  46. pyon/http/resource.py +50 -0
  47. pyon/http/response.py +38 -0
  48. pyon/router/Link.py +52 -0
  49. pyon/router/RouterView.py +65 -0
  50. pyon/router/__init__.py +5 -0
  51. pyon/router/core.py +93 -0
  52. pyon/router/utils.py +34 -0
  53. pyon/store/__init__.py +3 -0
  54. pyon/store/store.py +39 -0
  55. pyon_py-0.1.0.dist-info/METADATA +972 -0
  56. pyon_py-0.1.0.dist-info/RECORD +59 -0
  57. pyon_py-0.1.0.dist-info/WHEEL +4 -0
  58. pyon_py-0.1.0.dist-info/entry_points.txt +2 -0
  59. pyon_py-0.1.0.dist-info/licenses/LICENCE +21 -0
pyon/__init__.py ADDED
@@ -0,0 +1,12 @@
1
+ """
2
+ PyOn Framework
3
+ """
4
+ from .core.app import App
5
+ from .core.bus import EventEmitter
6
+ from .core.component import BaseProps, Component
7
+ from .core.vnode import VNode, h
8
+ from .router import Router
9
+ from .store import Store
10
+
11
+ __all__ = ["App", "BaseProps", "Component", "EventEmitter", "Router", "Store", "VNode", "h"]
12
+ __version__ = "0.1.0"
@@ -0,0 +1,4 @@
1
+ from ._protocol import FetchResponse
2
+ from .impl import fetch, ffi, js
3
+
4
+ __all__ = ["FetchResponse", "fetch", "ffi", "js"]
@@ -0,0 +1,46 @@
1
+ from .dom import (
2
+ _JSON,
3
+ JS,
4
+ Console,
5
+ Crypto,
6
+ CustomElementRegistry,
7
+ Document,
8
+ MediaQueryList,
9
+ Navigator,
10
+ Performance,
11
+ Screen,
12
+ ScreenOrientation,
13
+ ScrollToOptions,
14
+ Storage,
15
+ VisualViewport,
16
+ Window,
17
+ WindowHistory,
18
+ WindowLocation,
19
+ )
20
+ from .ffi import FFI, FFIProxy
21
+ from .http import AbortController, Fetch, FetchResponse
22
+
23
+ __all__ = [
24
+ "FFI",
25
+ "JS",
26
+ "_JSON",
27
+ "AbortController",
28
+ "Console",
29
+ "Crypto",
30
+ "CustomElementRegistry",
31
+ "Document",
32
+ "FFIProxy",
33
+ "Fetch",
34
+ "FetchResponse",
35
+ "MediaQueryList",
36
+ "Navigator",
37
+ "Performance",
38
+ "Screen",
39
+ "ScreenOrientation",
40
+ "ScrollToOptions",
41
+ "Storage",
42
+ "VisualViewport",
43
+ "Window",
44
+ "WindowHistory",
45
+ "WindowLocation",
46
+ ]
@@ -0,0 +1,484 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Any, Literal, Protocol, TypedDict, overload
4
+
5
+ if TYPE_CHECKING:
6
+ from pyon.core import DOMElement, DOMTextNode
7
+
8
+ class ScreenOrientation(Protocol):
9
+ """Protocol representing screen orientation in the browser."""
10
+ @property
11
+ def type(self) -> str: ...
12
+ @property
13
+ def angle(self) -> int: ...
14
+ def lock(self, orientation: str) -> Any: ...
15
+ def unlock(self) -> None: ...
16
+ def addEventListener(self, event: str, callback: Any) -> None: ...
17
+ def removeEventListener(self, event: str, callback: Any) -> None: ...
18
+
19
+ class Screen(Protocol):
20
+ """Protocol for the browser's Screen object (e.g. window.screen)."""
21
+ @property
22
+ def width(self) -> int: ...
23
+ @property
24
+ def height(self) -> int: ...
25
+ @property
26
+ def availWidth(self) -> int: ...
27
+ @property
28
+ def availHeight(self) -> int: ...
29
+ @property
30
+ def colorDepth(self) -> int: ...
31
+ @property
32
+ def pixelDepth(self) -> int: ...
33
+ @property
34
+ def orientation(self) -> ScreenOrientation: ...
35
+
36
+ class VisualViewport(Protocol):
37
+ """Protocol for the VisualViewport object."""
38
+ @property
39
+ def offsetLeft(self) -> float: ...
40
+ @property
41
+ def offsetTop(self) -> float: ...
42
+ @property
43
+ def pageLeft(self) -> float: ...
44
+ @property
45
+ def pageTop(self) -> float: ...
46
+ @property
47
+ def width(self) -> float: ...
48
+ @property
49
+ def height(self) -> float: ...
50
+ @property
51
+ def scale(self) -> float: ...
52
+ def addEventListener(self, event: str, callback: Any) -> None: ...
53
+ def removeEventListener(self, event: str, callback: Any) -> None: ...
54
+
55
+ class MediaQueryList(Protocol):
56
+ """Protocol for the MediaQueryList object."""
57
+ @property
58
+ def matches(self) -> bool: ...
59
+ @property
60
+ def media(self) -> str: ...
61
+ def addEventListener(self, event: str, callback: Any) -> None: ...
62
+ def removeEventListener(self, event: str, callback: Any) -> None: ...
63
+ def addListener(self, callback: Any) -> None: ...
64
+ def removeListener(self, callback: Any) -> None: ...
65
+
66
+ class Storage(Protocol):
67
+ """Protocol for the Web Storage API (localStorage / sessionStorage)."""
68
+ @property
69
+ def length(self) -> int: ...
70
+ def key(self, index: int) -> str | None: ...
71
+ def getItem(self, key: str) -> str | None: ...
72
+ def setItem(self, key: str, value: str) -> None: ...
73
+ def removeItem(self, key: str) -> None: ...
74
+ def clear(self) -> None: ...
75
+
76
+ class Console(Protocol):
77
+ """Protocol for the Console object (window.console)."""
78
+ def log(self, *args: Any) -> None: ...
79
+ def warn(self, *args: Any) -> None: ...
80
+ def error(self, *args: Any) -> None: ...
81
+ def info(self, *args: Any) -> None: ...
82
+ def debug(self, *args: Any) -> None: ...
83
+ def trace(self, *args: Any) -> None: ...
84
+ def dir(self, obj: Any, options: Any = None) -> None: ...
85
+ def dirxml(self, *args: Any) -> None: ...
86
+ def table(self, data: Any, columns: list[str] | None = None) -> None: ...
87
+ def count(self, label: str = "") -> None: ...
88
+ def countReset(self, label: str = "") -> None: ...
89
+ def group(self, *args: Any) -> None: ...
90
+ def groupCollapsed(self, *args: Any) -> None: ...
91
+ def groupEnd(self) -> None: ...
92
+ def time(self, label: str = "") -> None: ...
93
+ def timeLog(self, label: str = "", *args: Any) -> None: ...
94
+ def timeEnd(self, label: str = "") -> None: ...
95
+ def clear(self) -> None: ...
96
+ # assert_ maps to console.assert in JS (avoids the Python keyword)
97
+ def assert_(self, condition: bool, *args: Any) -> None: ...
98
+ def profile(self, label: str = "") -> None: ...
99
+ def profileEnd(self, label: str = "") -> None: ...
100
+
101
+ class Performance(Protocol):
102
+ """Protocol for the Performance object."""
103
+ @property
104
+ def timeOrigin(self) -> float: ...
105
+ @property
106
+ def timing(self) -> Any: ...
107
+ @property
108
+ def navigation(self) -> Any: ...
109
+ def now(self) -> float: ...
110
+ def mark(self, name: str, markOptions: Any = None) -> Any: ...
111
+ def measure(self, measureName: str, startOrMeasureOptions: Any = None, endMark: str = "") -> Any: ...
112
+ def clearMarks(self, name: str = "") -> None: ...
113
+ def clearMeasures(self, name: str = "") -> None: ...
114
+ def getEntries(self) -> Any: ...
115
+ def getEntriesByName(self, name: str, type: str = "") -> Any: ...
116
+ def getEntriesByType(self, type: str) -> Any: ...
117
+
118
+ class Crypto(Protocol):
119
+ """Protocol for the Crypto object."""
120
+ @property
121
+ def subtle(self) -> Any: ...
122
+ def getRandomValues(self, array: Any) -> Any: ...
123
+ def randomUUID(self) -> str: ...
124
+
125
+ class CustomElementRegistry(Protocol):
126
+ """Protocol for CustomElementRegistry."""
127
+ def define(self, name: str, constructor: Any, options: Any = None) -> None: ...
128
+ def get(self, name: str) -> Any: ...
129
+ def getName(self, constructor: Any) -> str | None: ...
130
+ def whenDefined(self, name: str) -> Any: ...
131
+ def upgrade(self, root: Any) -> None: ...
132
+
133
+ class Navigator(Protocol):
134
+ """Protocol for the browser's Navigator object."""
135
+ @property
136
+ def userAgent(self) -> str: ...
137
+ @property
138
+ def language(self) -> str: ...
139
+ @property
140
+ def languages(self) -> list[str]: ...
141
+ @property
142
+ def platform(self) -> str: ...
143
+ @property
144
+ def vendor(self) -> str: ...
145
+ @property
146
+ def cookieEnabled(self) -> bool: ...
147
+ @property
148
+ def onLine(self) -> bool: ...
149
+ @property
150
+ def maxTouchPoints(self) -> int: ...
151
+ @property
152
+ def hardwareConcurrency(self) -> int: ...
153
+ @property
154
+ def deviceMemory(self) -> float: ...
155
+ @property
156
+ def pdfViewerEnabled(self) -> bool: ...
157
+ @property
158
+ def webdriver(self) -> bool: ...
159
+ @property
160
+ def clipboard(self) -> Any: ...
161
+ @property
162
+ def credentials(self) -> Any: ...
163
+ @property
164
+ def geolocation(self) -> Any: ...
165
+ @property
166
+ def mediaDevices(self) -> Any: ...
167
+ @property
168
+ def permissions(self) -> Any: ...
169
+ @property
170
+ def serviceWorker(self) -> Any: ...
171
+ @property
172
+ def storage(self) -> Any: ...
173
+ @property
174
+ def locks(self) -> Any: ...
175
+ @property
176
+ def mediaCapabilities(self) -> Any: ...
177
+ @property
178
+ def connection(self) -> Any: ...
179
+
180
+ def sendBeacon(self, url: str, data: Any = None) -> bool: ...
181
+ def vibrate(self, pattern: Any) -> bool: ...
182
+ def share(self, data: Any = None) -> Any: ...
183
+ def canShare(self, data: Any = None) -> bool: ...
184
+ def getBattery(self) -> Any: ...
185
+ def getGamepads(self) -> Any: ...
186
+ def requestMediaKeySystemAccess(self, keySystem: str, supportedConfigurations: Any) -> Any: ...
187
+ def registerProtocolHandler(self, scheme: str, url: str) -> None: ...
188
+
189
+ class Document(Protocol):
190
+ """Protocol for the browser's Document object model."""
191
+ @property
192
+ def body(self) -> DOMElement: ...
193
+ @property
194
+ def head(self) -> DOMElement: ...
195
+ @property
196
+ def title(self) -> str: ...
197
+ @title.setter
198
+ def title(self, value: str) -> None: ...
199
+ @property
200
+ def documentElement(self) -> DOMElement: ...
201
+ @property
202
+ def activeElement(self) -> DOMElement | None: ...
203
+ @property
204
+ def fullscreenElement(self) -> DOMElement | None: ...
205
+ @property
206
+ def pointerLockElement(self) -> DOMElement | None: ...
207
+ @property
208
+ def readyState(self) -> str: ...
209
+ @property
210
+ def referrer(self) -> str: ...
211
+ @property
212
+ def URL(self) -> str: ...
213
+ @property
214
+ def domain(self) -> str: ...
215
+ @property
216
+ def cookie(self) -> str: ...
217
+ @cookie.setter
218
+ def cookie(self, value: str) -> None: ...
219
+ @property
220
+ def lastModified(self) -> str: ...
221
+ @property
222
+ def characterSet(self) -> str: ...
223
+ @property
224
+ def contentType(self) -> str: ...
225
+ @property
226
+ def doctype(self) -> Any: ...
227
+ @property
228
+ def forms(self) -> Any: ...
229
+ @property
230
+ def images(self) -> Any: ...
231
+ @property
232
+ def links(self) -> Any: ...
233
+ @property
234
+ def scripts(self) -> Any: ...
235
+ @property
236
+ def styleSheets(self) -> Any: ...
237
+ @property
238
+ def visibilityState(self) -> str: ...
239
+ @property
240
+ def hidden(self) -> bool: ...
241
+ @property
242
+ def designMode(self) -> str: ...
243
+ @designMode.setter
244
+ def designMode(self, value: str) -> None: ...
245
+ @property
246
+ def dir(self) -> str: ...
247
+ @dir.setter
248
+ def dir(self, value: str) -> None: ...
249
+
250
+ def getElementById(self, id: str) -> DOMElement | None: ...
251
+ def getElementsByClassName(self, classNames: str) -> Any: ...
252
+ def getElementsByTagName(self, tagName: str) -> Any: ...
253
+ def getElementsByName(self, elementName: str) -> Any: ...
254
+ def querySelector(self, selectors: str) -> DOMElement | None: ...
255
+ def querySelectorAll(self, selectors: str) -> Any: ...
256
+ def createElement(self, tag: str) -> DOMElement: ...
257
+ def createTextNode(self, text: str) -> DOMTextNode: ...
258
+ def createDocumentFragment(self) -> Any: ...
259
+ def createComment(self, data: str) -> Any: ...
260
+ def createEvent(self, type: str) -> Any: ...
261
+ def createRange(self) -> Any: ...
262
+ def adoptNode(self, externalNode: Any) -> Any: ...
263
+ def importNode(self, externalNode: Any, deep: bool = False) -> Any: ...
264
+ def write(self, *text: str) -> None: ...
265
+ def writeln(self, *text: str) -> None: ...
266
+ def open(self) -> Any: ...
267
+ def close(self) -> None: ...
268
+ def hasFocus(self) -> bool: ...
269
+ def getSelection(self) -> Any: ...
270
+ def elementFromPoint(self, x: float, y: float) -> DOMElement | None: ...
271
+ def elementsFromPoint(self, x: float, y: float) -> Any: ...
272
+ def exitFullscreen(self) -> Any: ...
273
+ def exitPointerLock(self) -> None: ...
274
+ def execCommand(self, commandId: str, showUI: bool = False, value: str = "") -> bool: ...
275
+ def queryCommandEnabled(self, commandId: str) -> bool: ...
276
+ def queryCommandState(self, commandId: str) -> bool: ...
277
+ def queryCommandValue(self, commandId: str) -> str: ...
278
+
279
+ def addEventListener(self, event: str, callback: Any) -> None: ...
280
+ def removeEventListener(self, event: str, callback: Any) -> None: ...
281
+ def dispatchEvent(self, event: Any) -> bool: ...
282
+
283
+ class WindowLocation(Protocol):
284
+ """Protocol for window.location."""
285
+ @property
286
+ def href(self) -> str: ...
287
+ @href.setter
288
+ def href(self, value: str) -> None: ...
289
+ @property
290
+ def pathname(self) -> str: ...
291
+ @property
292
+ def host(self) -> str: ...
293
+ @property
294
+ def hostname(self) -> str: ...
295
+ @property
296
+ def port(self) -> str: ...
297
+ @property
298
+ def protocol(self) -> str: ...
299
+ @property
300
+ def search(self) -> str: ...
301
+ @property
302
+ def hash(self) -> str: ...
303
+ @property
304
+ def origin(self) -> str: ...
305
+
306
+ def assign(self, url: str) -> None: ...
307
+ def reload(self) -> None: ...
308
+ def replace(self, url: str) -> None: ...
309
+ def toString(self) -> str: ...
310
+
311
+ class WindowHistory(Protocol):
312
+ """Protocol for window.history."""
313
+ @property
314
+ def length(self) -> int: ...
315
+ @property
316
+ def scrollRestoration(self) -> str: ...
317
+ @property
318
+ def state(self) -> Any: ...
319
+
320
+ def back(self) -> None: ...
321
+ def forward(self) -> None: ...
322
+ def go(self, delta: int) -> None: ...
323
+ def pushState(self, data: Any, title: str, url: str) -> None: ...
324
+ def replaceState(self, data: Any, title: str, url: str) -> None: ...
325
+
326
+ class ScrollToOptions(TypedDict, total=False):
327
+ """Options for scroll movement."""
328
+ top: float
329
+ left: float
330
+ behavior: Literal["auto", "smooth", "instant"]
331
+
332
+ class Window(Protocol):
333
+ """Comprehensive protocol for the Window object (browser window)."""
334
+ @property
335
+ def document(self) -> Document: ...
336
+ @property
337
+ def location(self) -> WindowLocation: ...
338
+ @property
339
+ def history(self) -> WindowHistory: ...
340
+ @property
341
+ def navigator(self) -> Navigator: ...
342
+ @property
343
+ def screen(self) -> Screen: ...
344
+ @property
345
+ def performance(self) -> Performance: ...
346
+ @property
347
+ def localStorage(self) -> Storage: ...
348
+ @property
349
+ def sessionStorage(self) -> Storage: ...
350
+ @property
351
+ def console(self) -> Console: ...
352
+ @property
353
+ def crypto(self) -> Crypto: ...
354
+ @property
355
+ def customElements(self) -> CustomElementRegistry: ...
356
+ @property
357
+ def visualViewport(self) -> VisualViewport | None: ...
358
+
359
+ @property
360
+ def innerWidth(self) -> int: ...
361
+ @property
362
+ def innerHeight(self) -> int: ...
363
+ @property
364
+ def outerWidth(self) -> int: ...
365
+ @property
366
+ def outerHeight(self) -> int: ...
367
+ @property
368
+ def screenX(self) -> int: ...
369
+ @property
370
+ def screenY(self) -> int: ...
371
+ @property
372
+ def screenLeft(self) -> int: ...
373
+ @property
374
+ def screenTop(self) -> int: ...
375
+ @property
376
+ def scrollX(self) -> float: ...
377
+ @property
378
+ def scrollY(self) -> float: ...
379
+ @property
380
+ def pageXOffset(self) -> float: ...
381
+ @property
382
+ def pageYOffset(self) -> float: ...
383
+ @property
384
+ def devicePixelRatio(self) -> float: ...
385
+
386
+ @property
387
+ def frameElement(self) -> DOMElement | None: ...
388
+ @property
389
+ def frames(self) -> Window: ...
390
+ @property
391
+ def length(self) -> int: ...
392
+ @property
393
+ def name(self) -> str: ...
394
+ @name.setter
395
+ def name(self, value: str) -> None: ...
396
+ @property
397
+ def opener(self) -> Any: ...
398
+ @property
399
+ def parent(self) -> Window: ...
400
+ # self_ maps to window.self in JS (avoids the Python keyword)
401
+ @property
402
+ def self_(self) -> Window: ...
403
+ @property
404
+ def top(self) -> Window | None: ...
405
+
406
+ @property
407
+ def closed(self) -> bool: ...
408
+ @property
409
+ def isSecureContext(self) -> bool: ...
410
+ @property
411
+ def origin(self) -> str: ...
412
+ @property
413
+ def crossOriginIsolated(self) -> bool: ...
414
+
415
+ def alert(self, message: str = "") -> None: ...
416
+ def confirm(self, message: str = "") -> bool: ...
417
+ def prompt(self, message: str = "", default: str = "") -> str | None: ...
418
+ def open(self, url: str = "", target: str = "_blank", features: str = "") -> Window | None: ...
419
+ def close(self) -> None: ...
420
+ def stop(self) -> None: ...
421
+ def focus(self) -> None: ...
422
+ def blur(self) -> None: ...
423
+ # print_ maps to window.print in JS
424
+ def print_(self) -> None: ...
425
+ def postMessage(self, message: Any, targetOrigin: str, transfer: Any = None) -> None: ...
426
+
427
+ def requestAnimationFrame(self, callback: Any) -> int: ...
428
+ def cancelAnimationFrame(self, handle: int) -> None: ...
429
+ def setTimeout(self, callback: Any, delay: int = 0, *args: Any) -> int: ...
430
+ def clearTimeout(self, handle: int) -> None: ...
431
+ def setInterval(self, callback: Any, delay: int = 0, *args: Any) -> int: ...
432
+ def clearInterval(self, handle: int) -> None: ...
433
+ def queueMicrotask(self, callback: Any) -> None: ...
434
+
435
+ def fetch(self, resource: Any, options: Any = None) -> Any: ...
436
+ def atob(self, data: str) -> str: ...
437
+ def btoa(self, data: str) -> str: ...
438
+
439
+ def getComputedStyle(self, element: Any, pseudoElt: str | None = None) -> Any: ...
440
+ def matchMedia(self, query: str) -> MediaQueryList: ...
441
+ def requestIdleCallback(self, callback: Any, options: Any = None) -> int: ...
442
+ def cancelIdleCallback(self, handle: int) -> None: ...
443
+ def getSelection(self) -> Any: ...
444
+ def structuredClone(self, value: Any, options: Any = None) -> Any: ...
445
+ def createImageBitmap(self, image: Any, options: Any = None) -> Any: ...
446
+
447
+ def addEventListener(self, event: str, callback: Any) -> None: ...
448
+ def removeEventListener(self, event: str, callback: Any) -> None: ...
449
+
450
+ @overload
451
+ def scrollTo(self, x: float, y: float) -> None: ...
452
+ @overload
453
+ def scrollTo(self, options: ScrollToOptions) -> None: ...
454
+ def scrollTo(self, *args: Any, **kwargs: Any) -> None: ...
455
+
456
+ @overload
457
+ def scrollBy(self, x: float, y: float) -> None: ...
458
+ @overload
459
+ def scrollBy(self, options: ScrollToOptions) -> None: ...
460
+ def scrollBy(self, *args: Any, **kwargs: Any) -> None: ...
461
+
462
+ @overload
463
+ def scroll(self, x: float, y: float) -> None: ...
464
+ @overload
465
+ def scroll(self, options: ScrollToOptions) -> None: ...
466
+ def scroll(self, *args: Any, **kwargs: Any) -> None: ...
467
+
468
+
469
+ class _JSON(Protocol):
470
+ """Protocol for the global JSON object."""
471
+ def parse(self, text: str) -> Any: ...
472
+
473
+ class JS(Protocol):
474
+ """Protocol for the JS global (root) scope."""
475
+ @property
476
+ def document(self) -> Document: ...
477
+ @property
478
+ def window(self) -> Window: ...
479
+ @property
480
+ def console(self) -> Console: ...
481
+ @property
482
+ def JSON(self) -> _JSON: ...
483
+
484
+ def queueMicrotask(self, callback: Any) -> None: ...
@@ -0,0 +1,29 @@
1
+ from collections.abc import Callable
2
+ from typing import Any, Protocol
3
+
4
+
5
+ class FFIProxy(Protocol):
6
+ """Protocol for FFI Proxy object that wraps Python callable.
7
+ Used as an event listener callback on the JavaScript side.
8
+ """
9
+ def destroy(self) -> None:
10
+ """Destroy the proxy, preventing memory leaks."""
11
+ ...
12
+
13
+
14
+ class FFI(Protocol):
15
+ """Protocol for FFI interop Python <-> JS.
16
+ In Pyodide, this is implemented by the `pyodide.ffi` module.
17
+ """
18
+
19
+ def create_proxy(self, obj: Callable[..., Any]) -> FFIProxy:
20
+ """Wrap a Python callable into a JavaScript proxy to be used
21
+ as an event listener callback on the JavaScript side or a queueMicrotask.
22
+ """
23
+ ...
24
+
25
+ def to_js(self, obj: Any, dict_converter: Any = ...) -> Any:
26
+ """Translate Python primitive/collection type into native JS object/array.
27
+ (Currently not used in UI, but important for API HTTP in the future).
28
+ """
29
+ ...
@@ -0,0 +1,52 @@
1
+ from collections.abc import Coroutine
2
+ from typing import Any, Protocol
3
+
4
+
5
+ class AbortController(Protocol):
6
+ """
7
+ Protocol for the AbortController class.
8
+ """
9
+ @property
10
+ def signal(self) -> Any: ...
11
+ def abort(self) -> None: ...
12
+
13
+
14
+ class FetchResponse(Protocol):
15
+ """
16
+ Protocol for the response object returned by pyfetch.
17
+ """
18
+ @property
19
+ def ok(self) -> bool: ...
20
+
21
+ @property
22
+ def status(self) -> int: ...
23
+
24
+ @property
25
+ def status_text(self) -> str: ...
26
+
27
+ @property
28
+ def url(self) -> str: ...
29
+
30
+ @property
31
+ def headers(self) -> Any: ...
32
+
33
+ async def json(self) -> Any: ...
34
+ async def string(self) -> str: ...
35
+ async def bytes(self) -> bytes: ...
36
+ async def memoryview(self) -> memoryview: ...
37
+ async def clone(self) -> "FetchResponse": ...
38
+
39
+
40
+ class Fetch(Protocol):
41
+ """
42
+ Protocol for the fetch function itself.
43
+ """
44
+ def __call__(
45
+ self,
46
+ request: str,
47
+ /,
48
+ *,
49
+ signal: Any = None,
50
+ fetcher: Any = None,
51
+ **kwargs: Any
52
+ ) -> Coroutine[Any, Any, FetchResponse]: ...
@@ -0,0 +1,52 @@
1
+ import sys
2
+ from collections.abc import Callable
3
+
4
+ from .._protocol import FFI, JS, AbortController
5
+ from .._protocol.http import Fetch
6
+
7
+ js: JS
8
+ ffi: FFI
9
+ fetch: Fetch
10
+ create_abort_controller: Callable[[], AbortController]
11
+
12
+ if sys.platform == "emscripten":
13
+ from .pyodide_impl import PyodideFFI, PyodideJS
14
+ from .pyodide_impl import create_abort_controller as pyodide_create_abort_controller
15
+ js = PyodideJS()
16
+ ffi = PyodideFFI()
17
+ from pyodide.http import pyfetch as fetch
18
+
19
+ create_abort_controller = pyodide_create_abort_controller
20
+ else:
21
+ class MockJS:
22
+ document = None
23
+ window = None
24
+ JSON = None
25
+ def queueMicrotask(self, callback):
26
+ raise NotImplementedError("Browser environment not available")
27
+
28
+ class MockFFI:
29
+ def create_proxy(self, obj):
30
+ return obj
31
+ def to_js(self, obj, dict_converter=None):
32
+ return obj
33
+
34
+ js = MockJS() # type: ignore
35
+ ffi = MockFFI() # type: ignore
36
+
37
+ from typing import Any
38
+ async def mock_pyfetch(request: str, /, *, signal: Any = None, fetcher: Any = None, **kwargs: Any) -> Any:
39
+ raise NotImplementedError("Browser environment not available")
40
+
41
+ fetch = mock_pyfetch
42
+
43
+ def mock_create_abort_controller():
44
+ class MockAbortController:
45
+ signal = None
46
+ def abort(self):
47
+ pass
48
+ return MockAbortController()
49
+
50
+ create_abort_controller = mock_create_abort_controller
51
+
52
+ __all__ = ["create_abort_controller", "fetch", "ffi", "js"]
@@ -0,0 +1,5 @@
1
+ from .ffi import PyodideFFI
2
+ from .http import PyodideAbortController, create_abort_controller
3
+ from .js import PyodideJS
4
+
5
+ __all__ = ["PyodideAbortController", "PyodideFFI", "PyodideJS", "create_abort_controller"]