utils.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. """Common utility functions used in the compiler."""
  2. from __future__ import annotations
  3. import json
  4. from typing import TYPE_CHECKING, Dict, Set, Type
  5. from pynecone import constants, utils
  6. from pynecone.compiler import templates
  7. from pynecone.components.base import (
  8. Body,
  9. DocumentHead,
  10. Head,
  11. Html,
  12. Link,
  13. Main,
  14. Script,
  15. Title,
  16. )
  17. from pynecone.components.component import ImportDict
  18. from pynecone.state import State
  19. from pynecone.style import Style
  20. if TYPE_CHECKING:
  21. from pynecone.components.component import Component
  22. # To re-export this function.
  23. merge_imports = utils.merge_imports
  24. def compile_import_statement(lib: str, fields: Set[str]) -> str:
  25. """Compile an import statement.
  26. Args:
  27. lib: The library to import from.
  28. fields: The set of fields to import from the library.
  29. Returns:
  30. The compiled import statement.
  31. """
  32. # Check for default imports.
  33. defaults = {
  34. field
  35. for field in fields
  36. if field.lower() == lib.lower().replace("-", "").replace("/", "")
  37. }
  38. assert len(defaults) < 2
  39. # Get the default import, and the specific imports.
  40. default = next(iter(defaults), "")
  41. rest = fields - defaults
  42. return templates.format_import(lib=lib, default=default, rest=rest)
  43. def compile_imports(imports: ImportDict) -> str:
  44. """Compile an import dict.
  45. Args:
  46. imports: The import dict to compile.
  47. Returns:
  48. The compiled import dict.
  49. """
  50. return templates.join(
  51. [compile_import_statement(lib, fields) for lib, fields in imports.items()]
  52. )
  53. def compile_constant_declaration(name: str, value: str) -> str:
  54. """Compile a constant declaration.
  55. Args:
  56. name: The name of the constant.
  57. value: The value of the constant.
  58. Returns:
  59. The compiled constant declaration.
  60. """
  61. return templates.CONST(name=name, value=json.dumps(value))
  62. def compile_constants() -> str:
  63. """Compile all the necessary constants.
  64. Returns:
  65. A string of all the compiled constants.
  66. """
  67. endpoint = constants.Endpoint.EVENT
  68. return templates.join(
  69. [compile_constant_declaration(name=endpoint.name, value=endpoint.get_url())]
  70. )
  71. import plotly.graph_objects as go
  72. def compile_state(state: Type[State]) -> str:
  73. """Compile the state of the app.
  74. Args:
  75. state: The app state object.
  76. Returns:
  77. A string of the compiled state.
  78. """
  79. initial_state = state().dict()
  80. initial_state.update(
  81. {
  82. "events": [{"name": utils.get_hydrate_event(state)}],
  83. }
  84. )
  85. initial_state = utils.format_state(initial_state)
  86. synced_state = templates.format_state(
  87. state=state.get_name(), initial_state=json.dumps(initial_state)
  88. )
  89. initial_result = {
  90. "state": None,
  91. "events": [],
  92. "processing": False,
  93. }
  94. result = templates.format_state(
  95. state="result",
  96. initial_state=json.dumps(initial_result),
  97. )
  98. router = templates.ROUTER
  99. return templates.join([synced_state, result, router])
  100. def compile_events(state: Type[State]) -> str:
  101. """Compile all the events for a given component.
  102. Args:
  103. state: The state class for the component.
  104. Returns:
  105. A string of the compiled events for the component.
  106. """
  107. state_name = state.get_name()
  108. state_setter = templates.format_state_setter(state_name)
  109. return templates.EVENT_FN(state=state_name, set_state=state_setter)
  110. def compile_effects(state: Type[State]) -> str:
  111. """Compile all the effects for a given component.
  112. Args:
  113. state: The state class for the component.
  114. Returns:
  115. A string of the compiled effects for the component.
  116. """
  117. state_name = state.get_name()
  118. result_name = "result"
  119. set_result = templates.format_state_setter(result_name)
  120. return templates.USE_EFFECT(
  121. state=state_name, result=result_name, set_result=set_result
  122. )
  123. def compile_render(component: Component) -> str:
  124. """Compile the component's render method.
  125. Args:
  126. component: The component to compile the render method for.
  127. Returns:
  128. A string of the compiled render method.
  129. """
  130. return component.render()
  131. def create_document_root(stylesheets) -> Component:
  132. """Create the document root.
  133. Args:
  134. stylesheets: The stylesheets to include in the document root.
  135. Returns:
  136. The document root.
  137. """
  138. sheets = [Link.create(rel="stylesheet", href=href) for href in stylesheets]
  139. return Html.create(
  140. DocumentHead.create(*sheets),
  141. Body.create(
  142. Main.create(),
  143. Script.create(),
  144. ),
  145. )
  146. def create_theme(style: Style) -> Dict:
  147. """Create the base style for the app.
  148. Args:
  149. style: The style dict for the app.
  150. Returns:
  151. The base style for the app.
  152. """
  153. return {
  154. "styles": {
  155. "global": Style({k: v for k, v in style.items() if not isinstance(k, type)})
  156. },
  157. }
  158. def add_title(page: Component, title: str) -> Component:
  159. """Add a title to a page.
  160. Args:
  161. page: The component for the page.
  162. title: The title to add.
  163. Returns:
  164. The component with the title added.
  165. """
  166. page.children.append(Head.create(Title.create(title)))
  167. return page