pulse-framework 0.1.62__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 (126) hide show
  1. pulse/__init__.py +1493 -0
  2. pulse/_examples.py +29 -0
  3. pulse/app.py +1086 -0
  4. pulse/channel.py +607 -0
  5. pulse/cli/__init__.py +0 -0
  6. pulse/cli/cmd.py +575 -0
  7. pulse/cli/dependencies.py +181 -0
  8. pulse/cli/folder_lock.py +134 -0
  9. pulse/cli/helpers.py +271 -0
  10. pulse/cli/logging.py +102 -0
  11. pulse/cli/models.py +35 -0
  12. pulse/cli/packages.py +262 -0
  13. pulse/cli/processes.py +292 -0
  14. pulse/cli/secrets.py +39 -0
  15. pulse/cli/uvicorn_log_config.py +87 -0
  16. pulse/code_analysis.py +38 -0
  17. pulse/codegen/__init__.py +0 -0
  18. pulse/codegen/codegen.py +359 -0
  19. pulse/codegen/templates/__init__.py +0 -0
  20. pulse/codegen/templates/layout.py +106 -0
  21. pulse/codegen/templates/route.py +345 -0
  22. pulse/codegen/templates/routes_ts.py +42 -0
  23. pulse/codegen/utils.py +20 -0
  24. pulse/component.py +237 -0
  25. pulse/components/__init__.py +0 -0
  26. pulse/components/for_.py +83 -0
  27. pulse/components/if_.py +86 -0
  28. pulse/components/react_router.py +94 -0
  29. pulse/context.py +108 -0
  30. pulse/cookies.py +322 -0
  31. pulse/decorators.py +344 -0
  32. pulse/dom/__init__.py +0 -0
  33. pulse/dom/elements.py +1024 -0
  34. pulse/dom/events.py +445 -0
  35. pulse/dom/props.py +1250 -0
  36. pulse/dom/svg.py +0 -0
  37. pulse/dom/tags.py +328 -0
  38. pulse/dom/tags.pyi +480 -0
  39. pulse/env.py +178 -0
  40. pulse/form.py +538 -0
  41. pulse/helpers.py +541 -0
  42. pulse/hooks/__init__.py +0 -0
  43. pulse/hooks/core.py +452 -0
  44. pulse/hooks/effects.py +88 -0
  45. pulse/hooks/init.py +668 -0
  46. pulse/hooks/runtime.py +464 -0
  47. pulse/hooks/setup.py +254 -0
  48. pulse/hooks/stable.py +138 -0
  49. pulse/hooks/state.py +192 -0
  50. pulse/js/__init__.py +125 -0
  51. pulse/js/__init__.pyi +115 -0
  52. pulse/js/_types.py +299 -0
  53. pulse/js/array.py +339 -0
  54. pulse/js/console.py +50 -0
  55. pulse/js/date.py +119 -0
  56. pulse/js/document.py +145 -0
  57. pulse/js/error.py +140 -0
  58. pulse/js/json.py +66 -0
  59. pulse/js/map.py +97 -0
  60. pulse/js/math.py +69 -0
  61. pulse/js/navigator.py +79 -0
  62. pulse/js/number.py +57 -0
  63. pulse/js/obj.py +81 -0
  64. pulse/js/object.py +172 -0
  65. pulse/js/promise.py +172 -0
  66. pulse/js/pulse.py +115 -0
  67. pulse/js/react.py +495 -0
  68. pulse/js/regexp.py +57 -0
  69. pulse/js/set.py +124 -0
  70. pulse/js/string.py +38 -0
  71. pulse/js/weakmap.py +53 -0
  72. pulse/js/weakset.py +48 -0
  73. pulse/js/window.py +205 -0
  74. pulse/messages.py +202 -0
  75. pulse/middleware.py +471 -0
  76. pulse/plugin.py +96 -0
  77. pulse/proxy.py +242 -0
  78. pulse/py.typed +0 -0
  79. pulse/queries/__init__.py +0 -0
  80. pulse/queries/client.py +609 -0
  81. pulse/queries/common.py +101 -0
  82. pulse/queries/effect.py +55 -0
  83. pulse/queries/infinite_query.py +1418 -0
  84. pulse/queries/mutation.py +295 -0
  85. pulse/queries/protocol.py +136 -0
  86. pulse/queries/query.py +1314 -0
  87. pulse/queries/store.py +120 -0
  88. pulse/react_component.py +88 -0
  89. pulse/reactive.py +1208 -0
  90. pulse/reactive_extensions.py +1172 -0
  91. pulse/render_session.py +768 -0
  92. pulse/renderer.py +584 -0
  93. pulse/request.py +205 -0
  94. pulse/routing.py +598 -0
  95. pulse/serializer.py +279 -0
  96. pulse/state.py +556 -0
  97. pulse/test_helpers.py +15 -0
  98. pulse/transpiler/__init__.py +111 -0
  99. pulse/transpiler/assets.py +81 -0
  100. pulse/transpiler/builtins.py +1029 -0
  101. pulse/transpiler/dynamic_import.py +130 -0
  102. pulse/transpiler/emit_context.py +49 -0
  103. pulse/transpiler/errors.py +96 -0
  104. pulse/transpiler/function.py +611 -0
  105. pulse/transpiler/id.py +18 -0
  106. pulse/transpiler/imports.py +341 -0
  107. pulse/transpiler/js_module.py +336 -0
  108. pulse/transpiler/modules/__init__.py +33 -0
  109. pulse/transpiler/modules/asyncio.py +57 -0
  110. pulse/transpiler/modules/json.py +24 -0
  111. pulse/transpiler/modules/math.py +265 -0
  112. pulse/transpiler/modules/pulse/__init__.py +5 -0
  113. pulse/transpiler/modules/pulse/tags.py +250 -0
  114. pulse/transpiler/modules/typing.py +63 -0
  115. pulse/transpiler/nodes.py +1987 -0
  116. pulse/transpiler/py_module.py +135 -0
  117. pulse/transpiler/transpiler.py +1100 -0
  118. pulse/transpiler/vdom.py +256 -0
  119. pulse/types/__init__.py +0 -0
  120. pulse/types/event_handler.py +50 -0
  121. pulse/user_session.py +386 -0
  122. pulse/version.py +69 -0
  123. pulse_framework-0.1.62.dist-info/METADATA +198 -0
  124. pulse_framework-0.1.62.dist-info/RECORD +126 -0
  125. pulse_framework-0.1.62.dist-info/WHEEL +4 -0
  126. pulse_framework-0.1.62.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,135 @@
1
+ """Python module transpilation system for transpiler.
2
+
3
+ Provides infrastructure for mapping Python modules (like `math`) to JavaScript equivalents.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ import ast
9
+ from collections.abc import Callable, Iterable
10
+ from types import ModuleType
11
+ from typing import TYPE_CHECKING, Any, ClassVar, cast, override
12
+
13
+ from pulse.transpiler.nodes import Expr, Primitive, Transformer
14
+
15
+ if TYPE_CHECKING:
16
+ from pulse.transpiler.transpiler import Transpiler
17
+
18
+
19
+ class PyModule(Expr):
20
+ """Expr for a Python module imported as a whole (e.g., `import math`).
21
+
22
+ Subclasses can define transpiler mappings as class attributes:
23
+ - Expr attributes are used directly
24
+ - Callable attributes are wrapped in Transformer
25
+ - Primitives are converted via Expr.of()
26
+
27
+ The transpiler dict is built automatically via __init_subclass__.
28
+ """
29
+
30
+ __slots__: tuple[str, str] = ("transpiler", "name")
31
+
32
+ # Class-level transpiler template, built by __init_subclass__
33
+ _transpiler: ClassVar[dict[str, Expr]] = {}
34
+
35
+ transpiler: dict[str, Expr]
36
+ name: str
37
+
38
+ def __init__(self, transpiler: dict[str, Expr] | None = None, name: str = ""):
39
+ self.transpiler = transpiler if transpiler is not None else {}
40
+ self.name = name
41
+
42
+ def __init_subclass__(cls, **kwargs: Any) -> None:
43
+ super().__init_subclass__(**kwargs)
44
+ cls._transpiler = {}
45
+ for attr_name in dir(cls):
46
+ if attr_name.startswith("_"):
47
+ continue
48
+ attr = getattr(cls, attr_name)
49
+ if isinstance(attr, Expr):
50
+ cls._transpiler[attr_name] = attr
51
+ elif callable(attr):
52
+ cls._transpiler[attr_name] = Transformer(
53
+ cast(Callable[..., Expr], attr), name=attr_name
54
+ )
55
+ elif isinstance(attr, (bool, int, float, str)) or attr is None:
56
+ cls._transpiler[attr_name] = Expr.of(attr)
57
+
58
+ @override
59
+ def emit(self, out: list[str]) -> None:
60
+ label = self.name or "PyModule"
61
+ raise TypeError(f"{label} cannot be emitted directly")
62
+
63
+ @override
64
+ def render(self):
65
+ label = self.name or "PyModule"
66
+ raise TypeError(f"{label} cannot be rendered directly")
67
+
68
+ @override
69
+ def transpile_call(
70
+ self,
71
+ args: list[ast.expr],
72
+ keywords: list[ast.keyword],
73
+ ctx: Transpiler,
74
+ ) -> Expr:
75
+ label = self.name or "PyModule"
76
+ raise TypeError(f"{label} cannot be called directly")
77
+
78
+ @override
79
+ def transpile_getattr(self, attr: str, ctx: Transpiler) -> Expr:
80
+ if attr not in self.transpiler:
81
+ label = self.name or "Module"
82
+ raise TypeError(f"{label} has no attribute '{attr}'")
83
+ return self.transpiler[attr]
84
+
85
+ @override
86
+ def transpile_subscript(self, key: ast.expr, ctx: Transpiler) -> Expr:
87
+ label = self.name or "PyModule"
88
+ raise TypeError(f"{label} cannot be subscripted")
89
+
90
+ @staticmethod
91
+ def _build_transpiler(items: Iterable[tuple[str, Any]]) -> dict[str, Expr]:
92
+ """Build transpiler dict from name/value pairs."""
93
+ result: dict[str, Expr] = {}
94
+ for attr_name, attr in items:
95
+ if isinstance(attr, Expr):
96
+ result[attr_name] = attr
97
+ elif callable(attr):
98
+ result[attr_name] = Transformer(
99
+ cast(Callable[..., Expr], attr), name=attr_name
100
+ )
101
+ elif isinstance(attr, (bool, int, float, str)) or attr is None:
102
+ result[attr_name] = Expr.of(attr)
103
+ return result
104
+
105
+ @staticmethod
106
+ def register( # pyright: ignore[reportIncompatibleMethodOverride, reportImplicitOverride]
107
+ module: ModuleType,
108
+ transpilation: type[PyModule]
109
+ | dict[str, Expr | Primitive | Callable[..., Expr]],
110
+ ) -> None:
111
+ """Register a Python module for transpilation.
112
+
113
+ Args:
114
+ module: The Python module to register (e.g., `math`)
115
+ transpilation: Either a PyModule subclass or a dict mapping attribute names to:
116
+ - Expr: used directly
117
+ - Primitive (bool, int, float, str, None): converted via Expr.of()
118
+ - Callable[..., Expr]: wrapped in Transformer
119
+ """
120
+ # Get transpiler dict - use pre-built _transpiler for PyModule subclasses
121
+ if isinstance(transpilation, dict):
122
+ transpiler_dict = PyModule._build_transpiler(transpilation.items())
123
+ elif hasattr(transpilation, "_transpiler"):
124
+ transpiler_dict = transpilation._transpiler
125
+ else:
126
+ raise TypeError("PyModule.register expects a PyModule subclass or dict")
127
+
128
+ # Register individual values for lookup by id
129
+ for attr_name, expr in transpiler_dict.items():
130
+ module_value = getattr(module, attr_name, None)
131
+ if module_value is not None:
132
+ Expr.register(module_value, expr)
133
+
134
+ # Register the module object itself
135
+ Expr.register(module, PyModule(transpiler_dict, name=module.__name__))