reflex 0.4.6a4__py3-none-any.whl → 0.4.7__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.

Potentially problematic release.


This version of reflex might be problematic. Click here for more details.

Files changed (69) hide show
  1. reflex/.templates/apps/blank/code/blank.py +1 -0
  2. reflex/.templates/jinja/custom_components/pyproject.toml.jinja2 +1 -1
  3. reflex/.templates/jinja/custom_components/src.py.jinja2 +8 -8
  4. reflex/.templates/jinja/web/pages/index.js.jinja2 +0 -4
  5. reflex/.templates/jinja/web/pages/stateful_component.js.jinja2 +2 -6
  6. reflex/.templates/web/utils/state.js +6 -1
  7. reflex/__init__.py +2 -0
  8. reflex/__init__.pyi +2 -0
  9. reflex/app.py +12 -16
  10. reflex/app.pyi +2 -0
  11. reflex/compiler/compiler.py +10 -11
  12. reflex/compiler/utils.py +3 -3
  13. reflex/components/chakra/forms/pininput.py +2 -1
  14. reflex/components/component.py +71 -104
  15. reflex/components/core/banner.py +1 -1
  16. reflex/components/core/upload.py +2 -1
  17. reflex/components/datadisplay/__init__.py +1 -0
  18. reflex/components/datadisplay/logo.py +49 -0
  19. reflex/components/el/elements/forms.py +7 -4
  20. reflex/components/el/elements/forms.pyi +0 -1
  21. reflex/components/lucide/icon.py +3 -2
  22. reflex/components/lucide/icon.pyi +2 -2
  23. reflex/components/markdown/markdown.py +10 -6
  24. reflex/components/markdown/markdown.pyi +0 -3
  25. reflex/components/radix/themes/components/select.py +10 -3
  26. reflex/config.py +1 -1
  27. reflex/config.pyi +1 -1
  28. reflex/constants/base.py +4 -5
  29. reflex/constants/base.pyi +94 -0
  30. reflex/constants/compiler.py +8 -0
  31. reflex/custom_components/custom_components.py +33 -38
  32. reflex/experimental/__init__.py +14 -0
  33. reflex/experimental/hooks.py +75 -0
  34. reflex/page.py +1 -1
  35. reflex/reflex.py +18 -32
  36. reflex/style.py +4 -4
  37. reflex/testing.py +1 -1
  38. reflex/utils/console.py +6 -4
  39. reflex/utils/exec.py +17 -1
  40. reflex/utils/export.py +0 -3
  41. reflex/utils/prerequisites.py +243 -43
  42. reflex/utils/processes.py +6 -1
  43. reflex/utils/telemetry.py +14 -2
  44. reflex/utils/types.py +3 -2
  45. reflex/vars.py +6 -6
  46. reflex/vars.pyi +2 -1
  47. {reflex-0.4.6a4.dist-info → reflex-0.4.7.dist-info}/METADATA +15 -10
  48. {reflex-0.4.6a4.dist-info → reflex-0.4.7.dist-info}/RECORD +51 -65
  49. {reflex-0.4.6a4.dist-info → reflex-0.4.7.dist-info}/WHEEL +1 -1
  50. reflex/.templates/apps/sidebar/README.md +0 -69
  51. reflex/.templates/apps/sidebar/assets/favicon.ico +0 -0
  52. reflex/.templates/apps/sidebar/assets/github.svg +0 -10
  53. reflex/.templates/apps/sidebar/assets/logo.svg +0 -68
  54. reflex/.templates/apps/sidebar/assets/paneleft.svg +0 -13
  55. reflex/.templates/apps/sidebar/assets/reflex_black.svg +0 -37
  56. reflex/.templates/apps/sidebar/assets/reflex_white.svg +0 -8
  57. reflex/.templates/apps/sidebar/code/__init__.py +0 -1
  58. reflex/.templates/apps/sidebar/code/components/__init__.py +0 -0
  59. reflex/.templates/apps/sidebar/code/components/sidebar.py +0 -152
  60. reflex/.templates/apps/sidebar/code/pages/__init__.py +0 -3
  61. reflex/.templates/apps/sidebar/code/pages/dashboard.py +0 -22
  62. reflex/.templates/apps/sidebar/code/pages/index.py +0 -18
  63. reflex/.templates/apps/sidebar/code/pages/settings.py +0 -61
  64. reflex/.templates/apps/sidebar/code/sidebar.py +0 -16
  65. reflex/.templates/apps/sidebar/code/styles.py +0 -60
  66. reflex/.templates/apps/sidebar/code/templates/__init__.py +0 -1
  67. reflex/.templates/apps/sidebar/code/templates/template.py +0 -145
  68. {reflex-0.4.6a4.dist-info → reflex-0.4.7.dist-info}/LICENSE +0 -0
  69. {reflex-0.4.6a4.dist-info → reflex-0.4.7.dist-info}/entry_points.txt +0 -0
@@ -133,7 +133,7 @@ class Markdown(Component):
133
133
  **props,
134
134
  )
135
135
 
136
- def get_custom_components(
136
+ def _get_all_custom_components(
137
137
  self, seen: set[str] | None = None
138
138
  ) -> set[CustomComponent]:
139
139
  """Get all the custom components used by the component.
@@ -144,11 +144,13 @@ class Markdown(Component):
144
144
  Returns:
145
145
  The set of custom components.
146
146
  """
147
- custom_components = super().get_custom_components(seen=seen)
147
+ custom_components = super()._get_all_custom_components(seen=seen)
148
148
 
149
149
  # Get the custom components for each tag.
150
150
  for component in self.component_map.values():
151
- custom_components |= component(_MOCK_ARG).get_custom_components(seen=seen)
151
+ custom_components |= component(_MOCK_ARG)._get_all_custom_components(
152
+ seen=seen
153
+ )
152
154
 
153
155
  return custom_components
154
156
 
@@ -183,7 +185,9 @@ class Markdown(Component):
183
185
 
184
186
  # Get the imports for each component.
185
187
  for component in self.component_map.values():
186
- imports = utils.merge_imports(imports, component(_MOCK_ARG).get_imports())
188
+ imports = utils.merge_imports(
189
+ imports, component(_MOCK_ARG)._get_all_imports()
190
+ )
187
191
 
188
192
  # Get the imports for the code components.
189
193
  imports = utils.merge_imports(
@@ -293,8 +297,8 @@ class Markdown(Component):
293
297
  hooks = set()
294
298
  for _component in self.component_map.values():
295
299
  comp = _component(_MOCK_ARG)
296
- hooks |= comp.get_hooks_internal()
297
- hooks |= comp.get_hooks()
300
+ hooks.update(comp._get_all_hooks_internal())
301
+ hooks.update(comp._get_all_hooks())
298
302
  formatted_hooks = "\n".join(hooks)
299
303
  return f"""
300
304
  function {self._get_component_map_name()} () {{
@@ -123,9 +123,6 @@ class Markdown(Component):
123
123
  The markdown component.
124
124
  """
125
125
  ...
126
- def get_custom_components(
127
- self, seen: set[str] | None = None
128
- ) -> set[CustomComponent]: ...
129
126
  def get_component(self, tag: str, **props) -> Component: ...
130
127
  def format_component(self, tag: str, **props) -> str: ...
131
128
  def format_component_map(self) -> dict[str, str]: ...
@@ -198,6 +198,15 @@ class HighLevelSelect(SelectRoot):
198
198
  Returns:
199
199
  The select component.
200
200
  """
201
+ trigger_prop_list = [
202
+ "placeholder",
203
+ "variant",
204
+ "radius",
205
+ "width",
206
+ "flex_shrink",
207
+ "custom_attrs",
208
+ ]
209
+
201
210
  content_props = {
202
211
  prop: props.pop(prop)
203
212
  for prop in ["high_contrast", "position"]
@@ -205,9 +214,7 @@ class HighLevelSelect(SelectRoot):
205
214
  }
206
215
 
207
216
  trigger_props = {
208
- prop: props.pop(prop)
209
- for prop in ["placeholder", "variant", "radius", "width", "flex_shrink"]
210
- if prop in props
217
+ prop: props.pop(prop) for prop in trigger_prop_list if prop in props
211
218
  }
212
219
 
213
220
  color_scheme = props.pop("color_scheme", None)
reflex/config.py CHANGED
@@ -299,7 +299,7 @@ class Config(Base):
299
299
 
300
300
  return updated_values
301
301
 
302
- def get_event_namespace(self) -> str | None:
302
+ def get_event_namespace(self) -> str:
303
303
  """Get the websocket event namespace.
304
304
 
305
305
  Returns:
reflex/config.pyi CHANGED
@@ -104,7 +104,7 @@ class Config(Base):
104
104
  @staticmethod
105
105
  def check_deprecated_values(**kwargs) -> None: ...
106
106
  def update_from_env(self) -> None: ...
107
- def get_event_namespace(self) -> str | None: ...
107
+ def get_event_namespace(self) -> str: ...
108
108
  def _set_persistent(self, **kwargs) -> None: ...
109
109
 
110
110
  def get_config(reload: bool = ...) -> Config: ...
reflex/constants/base.py CHANGED
@@ -88,12 +88,11 @@ class ReflexHostingCLI(SimpleNamespace):
88
88
  class Templates(SimpleNamespace):
89
89
  """Constants related to Templates."""
90
90
 
91
- # Dynamically get the enum values from the .templates folder
92
- template_dir = os.path.join(Reflex.ROOT_DIR, Reflex.MODULE_NAME, ".templates/apps")
93
- template_dirs = next(os.walk(template_dir))[1]
91
+ # The route on Reflex backend to query which templates are available and their URLs.
92
+ APP_TEMPLATES_ROUTE = "/app-templates"
94
93
 
95
- # Create an enum value for each directory in the .templates folder
96
- Kind = Enum("Kind", {template.upper(): template for template in template_dirs})
94
+ # The default template
95
+ DEFAULT = "blank"
97
96
 
98
97
  class Dirs(SimpleNamespace):
99
98
  """Folders used by the template system of Reflex."""
@@ -0,0 +1,94 @@
1
+ """Stub file for reflex/constants/base.py"""
2
+ # ------------------- DO NOT EDIT ----------------------
3
+ # This file was generated by `reflex/utils/pyi_generator.py`!
4
+ # ------------------------------------------------------
5
+
6
+ from typing import Any, Dict, Literal, Optional, Union, overload
7
+ from reflex.vars import Var, BaseVar, ComputedVar
8
+ from reflex.event import EventChain, EventHandler, EventSpec
9
+ from reflex.style import Style
10
+ import os
11
+ import platform
12
+ from enum import Enum
13
+ from importlib import metadata
14
+ from types import SimpleNamespace
15
+ from platformdirs import PlatformDirs
16
+
17
+ IS_WINDOWS = platform.system() == "Windows"
18
+
19
+ class Dirs(SimpleNamespace):
20
+ WEB = ".web"
21
+ APP_ASSETS = "assets"
22
+ UTILS = "utils"
23
+ STATIC = "_static"
24
+ STATE_PATH = "/".join([UTILS, "state"])
25
+ COMPONENTS_PATH = "/".join([UTILS, "components"])
26
+ CONTEXTS_PATH = "/".join([UTILS, "context"])
27
+ WEB_PAGES = os.path.join(WEB, "pages")
28
+ WEB_STATIC = os.path.join(WEB, STATIC)
29
+ WEB_UTILS = os.path.join(WEB, UTILS)
30
+ WEB_ASSETS = os.path.join(WEB, "public")
31
+ ENV_JSON = os.path.join(WEB, "env.json")
32
+ REFLEX_JSON = os.path.join(WEB, "reflex.json")
33
+ POSTCSS_JS = os.path.join(WEB, "postcss.config.js")
34
+
35
+ class Reflex(SimpleNamespace):
36
+ MODULE_NAME = "reflex"
37
+ VERSION = metadata.version(MODULE_NAME)
38
+ JSON = os.path.join(Dirs.WEB, "reflex.json")
39
+ _dir = os.environ.get("REFLEX_DIR", "")
40
+ DIR = _dir or PlatformDirs(MODULE_NAME, False).user_data_dir
41
+ ROOT_DIR = os.path.dirname(
42
+ os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
43
+ )
44
+
45
+ class ReflexHostingCLI(SimpleNamespace):
46
+ MODULE_NAME = "reflex-hosting-cli"
47
+
48
+ class Templates(SimpleNamespace):
49
+ APP_TEMPLATES_ROUTE = "/app-templates"
50
+ DEFAULT = "blank"
51
+
52
+ class Dirs(SimpleNamespace):
53
+ BASE = os.path.join(Reflex.ROOT_DIR, Reflex.MODULE_NAME, ".templates")
54
+ WEB_TEMPLATE = os.path.join(BASE, "web")
55
+ JINJA_TEMPLATE = os.path.join(BASE, "jinja")
56
+ CODE = "code"
57
+
58
+ class Next(SimpleNamespace):
59
+ CONFIG_FILE = "next.config.js"
60
+ SITEMAP_CONFIG_FILE = os.path.join(Dirs.WEB, "next-sitemap.config.js")
61
+ NODE_MODULES = "node_modules"
62
+ PACKAGE_LOCK = "package-lock.json"
63
+ FRONTEND_LISTENING_REGEX = "Local:[\\s]+(.*)"
64
+
65
+ class ColorMode(SimpleNamespace):
66
+ NAME = "colorMode"
67
+ USE = "useColorMode"
68
+ TOGGLE = "toggleColorMode"
69
+
70
+ class Env(str, Enum):
71
+ DEV = "dev"
72
+ PROD = "prod"
73
+
74
+ class LogLevel(str, Enum):
75
+ DEBUG = "debug"
76
+ INFO = "info"
77
+ WARNING = "warning"
78
+ ERROR = "error"
79
+ CRITICAL = "critical"
80
+
81
+ POLLING_MAX_HTTP_BUFFER_SIZE = 1000 * 1000
82
+
83
+ class Ping(SimpleNamespace):
84
+ INTERVAL = 25
85
+ TIMEOUT = 120
86
+
87
+ COOKIES = "cookies"
88
+ LOCAL_STORAGE = "local_storage"
89
+ SKIP_COMPILE_ENV_VAR = "__REFLEX_SKIP_COMPILE"
90
+ ENV_MODE_ENV_VAR = "REFLEX_ENV_MODE"
91
+ PYTEST_CURRENT_TEST = "PYTEST_CURRENT_TEST"
92
+ RELOAD_CONFIG = "__REFLEX_RELOAD_CONFIG"
93
+ REFLEX_VAR_OPENING_TAG = "<reflex.Var>"
94
+ REFLEX_VAR_CLOSING_TAG = "</reflex.Var>"
@@ -111,6 +111,14 @@ class Hooks(SimpleNamespace):
111
111
  """Common sets of hook declarations."""
112
112
 
113
113
  EVENTS = f"const [{CompileVars.ADD_EVENTS}, {CompileVars.CONNECT_ERROR}] = useContext(EventLoopContext);"
114
+ AUTOFOCUS = """
115
+ // Set focus to the specified element.
116
+ const focusRef = useRef(null)
117
+ useEffect(() => {
118
+ if (focusRef.current) {
119
+ focusRef.current.focus();
120
+ }
121
+ })"""
114
122
 
115
123
 
116
124
  class MemoizationDisposition(enum.Enum):
@@ -71,6 +71,28 @@ def _create_package_config(module_name: str, package_name: str):
71
71
  )
72
72
 
73
73
 
74
+ def _get_package_config(exit_on_fail: bool = True) -> dict:
75
+ """Get the package configuration from the pyproject.toml file.
76
+
77
+ Args:
78
+ exit_on_fail: Whether to exit if the pyproject.toml file is not found.
79
+
80
+ Returns:
81
+ The package configuration.
82
+
83
+ Raises:
84
+ Exit: If the pyproject.toml file is not found.
85
+ """
86
+ try:
87
+ with open(CustomComponents.PYPROJECT_TOML, "rb") as f:
88
+ return dict(tomlkit.load(f))
89
+ except (OSError, TOMLKitError) as ex:
90
+ console.error(f"Unable to read from pyproject.toml due to {ex}")
91
+ if exit_on_fail:
92
+ raise typer.Exit(code=1) from ex
93
+ raise
94
+
95
+
74
96
  def _create_readme(module_name: str, package_name: str):
75
97
  """Create a package README file.
76
98
 
@@ -145,7 +167,7 @@ def _populate_demo_app(name_variants: NameVariants):
145
167
 
146
168
  with set_directory(demo_app_dir):
147
169
  # We start with the blank template as basis.
148
- _init(name=demo_app_name, template=constants.Templates.Kind.BLANK)
170
+ _init(name=demo_app_name, template=constants.Templates.DEFAULT)
149
171
  # Then overwrite the app source file with the one we want for testing custom components.
150
172
  # This source file is rendered using jinja template file.
151
173
  with open(f"{demo_app_name}/{demo_app_name}.py", "w") as f:
@@ -416,9 +438,7 @@ def _run_commands_in_subprocess(cmds: list[str]) -> bool:
416
438
 
417
439
  def _make_pyi_files():
418
440
  """Create pyi files for the custom component."""
419
- from glob import glob
420
-
421
- package_name = glob("custom_components/*.egg-info")[0].replace(".egg-info", "")
441
+ package_name = _get_package_config()["project"]["name"]
422
442
 
423
443
  for dir, _, _ in os.walk(f"./{package_name}"):
424
444
  if "__pycache__" in dir:
@@ -514,22 +534,10 @@ def _validate_credentials(
514
534
  def _get_version_to_publish() -> str:
515
535
  """Get the version to publish from the pyproject.toml.
516
536
 
517
- Raises:
518
- Exit: If the version is not found in the pyproject.toml.
519
-
520
537
  Returns:
521
538
  The version to publish.
522
539
  """
523
- # Get the version from the pyproject.toml.
524
- try:
525
- with open(CustomComponents.PYPROJECT_TOML, "rb") as f:
526
- project_toml = tomlkit.parse(f.read())
527
- return project_toml.get("project", {})["version"]
528
- except (OSError, KeyError, TOMLKitError) as ex:
529
- console.error(
530
- f"Cannot find the version in {CustomComponents.PYPROJECT_TOML} due to {ex}"
531
- )
532
- raise typer.Exit(code=1) from ex
540
+ return _get_package_config()["project"]["version"]
533
541
 
534
542
 
535
543
  def _ensure_dist_dir(version_to_publish: str, build: bool):
@@ -715,7 +723,7 @@ def publish(
715
723
  _collect_details_for_gallery()
716
724
 
717
725
 
718
- def _process_entered_list(input: str) -> list | None:
726
+ def _process_entered_list(input: str | None) -> list | None:
719
727
  """Process the user entered comma separated list into a list if applicable.
720
728
 
721
729
  Args:
@@ -724,7 +732,7 @@ def _process_entered_list(input: str) -> list | None:
724
732
  Returns:
725
733
  The list of items or None.
726
734
  """
727
- return [t.strip() for t in input.split(",") if t if input] or None
735
+ return [t.strip() for t in (input or "").split(",") if t if input] or None
728
736
 
729
737
 
730
738
  def _validate_project_info():
@@ -733,12 +741,7 @@ def _validate_project_info():
733
741
  Raises:
734
742
  Exit: If the pyproject.toml file is ill-formed.
735
743
  """
736
- try:
737
- with open(CustomComponents.PYPROJECT_TOML, "rb") as f:
738
- pyproject_toml = tomlkit.parse(f.read())
739
- except TOMLKitError as ex:
740
- console.error(f"Unable to read from pyproject.toml due to {ex}")
741
- raise typer.Exit(code=1) from ex
744
+ pyproject_toml = _get_package_config()
742
745
 
743
746
  try:
744
747
  project = pyproject_toml.get("project", {})
@@ -773,6 +776,7 @@ def _validate_project_info():
773
776
  )
774
777
  or []
775
778
  )
779
+ project["keywords"] = new_keywords
776
780
  elif keyword_action == "a":
777
781
  new_keywords = (
778
782
  _process_entered_list(
@@ -780,7 +784,7 @@ def _validate_project_info():
780
784
  )
781
785
  or []
782
786
  )
783
- project["keywords"] = project.get("keywords", []) + new_keywords
787
+ project["keywords"] = project.get("keywords", []) + new_keywords
784
788
 
785
789
  if not project.get("urls"):
786
790
  project["urls"] = {}
@@ -795,7 +799,7 @@ def _validate_project_info():
795
799
  with open(CustomComponents.PYPROJECT_TOML, "w") as f:
796
800
  tomlkit.dump(pyproject_toml, f)
797
801
  except (OSError, TOMLKitError) as ex:
798
- console.error(f"Unable to read from pyproject.toml due to {ex}")
802
+ console.error(f"Unable to write to pyproject.toml due to {ex}")
799
803
  raise typer.Exit(code=1) from ex
800
804
 
801
805
 
@@ -815,10 +819,8 @@ def _collect_details_for_gallery():
815
819
  params = {}
816
820
  package_name = None
817
821
  try:
818
- with open(CustomComponents.PYPROJECT_TOML, "rb") as f:
819
- project_toml = tomlkit.parse(f.read())
820
- package_name = project_toml.get("project", {})["name"]
821
- except (OSError, TOMLKitError, KeyError) as ex:
822
+ package_name = _get_package_config(exit_on_fail=False)["project"]["name"]
823
+ except (TOMLKitError, KeyError) as ex:
822
824
  console.debug(
823
825
  f"Unable to read from pyproject.toml in current directory due to {ex}"
824
826
  )
@@ -849,13 +851,6 @@ def _collect_details_for_gallery():
849
851
  console.error(f"Unable to complete request due to {he}.")
850
852
  raise typer.Exit(code=1) from he
851
853
 
852
- display_name = (
853
- console.ask("[ Friendly display name for your component ] (enter to skip)")
854
- or None
855
- )
856
- if display_name:
857
- params["display_name"] = display_name
858
-
859
854
  files = []
860
855
  if (image_file_and_extension := _get_file_from_prompt_in_loop()) is not None:
861
856
  files.append(
@@ -0,0 +1,14 @@
1
+ """Namespace for experimental features."""
2
+
3
+ from types import SimpleNamespace
4
+
5
+ from ..utils.console import warn
6
+ from . import hooks as hooks
7
+
8
+ warn(
9
+ "`rx._x` contains experimental features and might be removed at any time in the future .",
10
+ )
11
+
12
+ _x = SimpleNamespace(
13
+ hooks=hooks,
14
+ )
@@ -0,0 +1,75 @@
1
+ """Add standard Hooks wrapper for React."""
2
+
3
+ from reflex.utils.imports import ImportVar
4
+ from reflex.vars import Var, VarData
5
+
6
+
7
+ def _add_react_import(v: Var | None, tags: str | list):
8
+ if v is None:
9
+ return
10
+
11
+ if isinstance(tags, str):
12
+ tags = [tags]
13
+
14
+ v._var_data = VarData( # type: ignore
15
+ imports={"react": [ImportVar(tag=tag) for tag in tags]},
16
+ )
17
+
18
+
19
+ def const(name, value) -> Var | None:
20
+ """Create a constant Var.
21
+
22
+ Args:
23
+ name: The name of the constant.
24
+ value: The value of the constant.
25
+
26
+ Returns:
27
+ The constant Var.
28
+ """
29
+ return Var.create(f"const {name} = {value}")
30
+
31
+
32
+ def useCallback(func, deps) -> Var | None:
33
+ """Create a useCallback hook with a function and dependencies.
34
+
35
+ Args:
36
+ func: The function to wrap.
37
+ deps: The dependencies of the function.
38
+
39
+ Returns:
40
+ The useCallback hook.
41
+ """
42
+ if deps:
43
+ v = Var.create(f"useCallback({func}, {deps})")
44
+ else:
45
+ v = Var.create(f"useCallback({func})")
46
+ _add_react_import(v, "useCallback")
47
+ return v
48
+
49
+
50
+ def useContext(context) -> Var | None:
51
+ """Create a useContext hook with a context.
52
+
53
+ Args:
54
+ context: The context to use.
55
+
56
+ Returns:
57
+ The useContext hook.
58
+ """
59
+ v = Var.create(f"useContext({context})")
60
+ _add_react_import(v, "useContext")
61
+ return v
62
+
63
+
64
+ def useRef(default) -> Var | None:
65
+ """Create a useRef hook with a default value.
66
+
67
+ Args:
68
+ default: The default value of the ref.
69
+
70
+ Returns:
71
+ The useRef hook.
72
+ """
73
+ v = Var.create(f"useRef({default})")
74
+ _add_react_import(v, "useRef")
75
+ return v
reflex/page.py CHANGED
@@ -30,7 +30,7 @@ def page(
30
30
  title: The title of the page.
31
31
  image: The favicon of the page.
32
32
  description: The description of the page.
33
- meta: Additionnal meta to add to the page.
33
+ meta: Additional meta to add to the page.
34
34
  on_load: The event handler(s) called when the page load.
35
35
  script_tags: scripts to attach to the page
36
36
 
reflex/reflex.py CHANGED
@@ -63,7 +63,7 @@ def main(
63
63
 
64
64
  def _init(
65
65
  name: str,
66
- template: constants.Templates.Kind | None = constants.Templates.Kind.BLANK,
66
+ template: str | None = None,
67
67
  loglevel: constants.LogLevel = config.loglevel,
68
68
  ):
69
69
  """Initialize a new Reflex app in the given directory."""
@@ -79,31 +79,20 @@ def _init(
79
79
  app_name = prerequisites.validate_app_name(name)
80
80
  console.rule(f"[bold]Initializing {app_name}")
81
81
 
82
+ # Check prerequisites.
82
83
  prerequisites.check_latest_package_version(constants.Reflex.MODULE_NAME)
83
-
84
84
  prerequisites.initialize_reflex_user_directory()
85
-
86
85
  prerequisites.ensure_reflex_installation_id()
87
86
 
88
87
  # When upgrading to 0.4, show migration instructions.
89
88
  if prerequisites.should_show_rx_chakra_migration_instructions():
90
89
  prerequisites.show_rx_chakra_migration_instructions()
91
90
 
92
- # Set up the app directory, only if the config doesn't exist.
93
- if not os.path.exists(constants.Config.FILE):
94
- if template is None:
95
- template = prerequisites.prompt_for_template()
96
- prerequisites.create_config(app_name)
97
- prerequisites.initialize_app_directory(app_name, template)
98
- telemetry_event = "init"
99
- else:
100
- telemetry_event = "reinit"
101
-
102
91
  # Set up the web project.
103
92
  prerequisites.initialize_frontend_dependencies()
104
93
 
105
- # Send the telemetry event after the .web folder is initialized.
106
- telemetry.send(telemetry_event)
94
+ # Initialize the app.
95
+ prerequisites.initialize_app(app_name, template)
107
96
 
108
97
  # Migrate Pynecone projects to Reflex.
109
98
  prerequisites.migrate_to_reflex()
@@ -123,7 +112,7 @@ def init(
123
112
  name: str = typer.Option(
124
113
  None, metavar="APP_NAME", help="The name of the app to initialize."
125
114
  ),
126
- template: constants.Templates.Kind = typer.Option(
115
+ template: str = typer.Option(
127
116
  None,
128
117
  help="The template to initialize the app with.",
129
118
  ),
@@ -165,7 +154,8 @@ def _run(
165
154
  _skip_compile()
166
155
 
167
156
  # Check that the app is initialized.
168
- prerequisites.check_initialized(frontend=frontend)
157
+ if prerequisites.needs_reinit(frontend=frontend):
158
+ _init(name=config.app_name, loglevel=loglevel)
169
159
 
170
160
  # If something is running on the ports, ask the user if they want to kill or change it.
171
161
  if frontend and processes.is_process_on_port(frontend_port):
@@ -234,6 +224,11 @@ def _run(
234
224
  # In dev mode, run the backend on the main thread.
235
225
  if backend and env == constants.Env.DEV:
236
226
  backend_cmd(backend_host, int(backend_port))
227
+ # The windows uvicorn bug workaround
228
+ # https://github.com/reflex-dev/reflex/issues/2335
229
+ if constants.IS_WINDOWS and exec.frontend_process:
230
+ # Sends SIGTERM in windows
231
+ exec.kill(exec.frontend_process.pid)
237
232
 
238
233
 
239
234
  @cli.command()
@@ -289,6 +284,10 @@ def export(
289
284
  ):
290
285
  """Export the app to a zip file."""
291
286
  from reflex.utils import export as export_utils
287
+ from reflex.utils import prerequisites
288
+
289
+ if prerequisites.needs_reinit(frontend=True):
290
+ _init(name=config.app_name, loglevel=loglevel)
292
291
 
293
292
  export_utils.export(
294
293
  zipping=zipping,
@@ -524,7 +523,8 @@ def deploy(
524
523
  dependency.check_requirements()
525
524
 
526
525
  # Check if we are set up.
527
- prerequisites.check_initialized(frontend=True)
526
+ if prerequisites.needs_reinit(frontend=True):
527
+ _init(name=config.app_name, loglevel=loglevel)
528
528
  prerequisites.check_latest_package_version(constants.ReflexHostingCLI.MODULE_NAME)
529
529
 
530
530
  hosting_cli.deploy(
@@ -565,20 +565,6 @@ def demo(
565
565
  # Open the demo app in a terminal.
566
566
  webbrowser.open("https://demo.reflex.run")
567
567
 
568
- # Later: open the demo app locally.
569
- # with tempfile.TemporaryDirectory() as tmp_dir:
570
- # os.chdir(tmp_dir)
571
- # _init(
572
- # name="reflex_demo",
573
- # template=constants.Templates.Kind.DEMO,
574
- # loglevel=constants.LogLevel.DEBUG,
575
- # )
576
- # _run(
577
- # frontend_port=frontend_port,
578
- # backend_port=backend_port,
579
- # loglevel=constants.LogLevel.DEBUG,
580
- # )
581
-
582
568
 
583
569
  cli.add_typer(db_cli, name="db", help="Subcommands for managing the database schema.")
584
570
  cli.add_typer(script_cli, name="script", help="Subcommands running helper scripts.")
reflex/style.py CHANGED
@@ -22,7 +22,7 @@ color_mode_var_data = VarData( # type: ignore
22
22
  "react": {ImportVar(tag="useContext")},
23
23
  },
24
24
  hooks={
25
- f"const [ {constants.ColorMode.NAME}, {constants.ColorMode.TOGGLE} ] = useContext(ColorModeContext)",
25
+ f"const [ {constants.ColorMode.NAME}, {constants.ColorMode.TOGGLE} ] = useContext(ColorModeContext)": None,
26
26
  },
27
27
  )
28
28
  # Var resolves to the current color mode for the app ("light" or "dark")
@@ -240,9 +240,9 @@ def format_as_emotion(style_dict: dict[str, Any]) -> Style | None:
240
240
  if isinstance(value, list):
241
241
  # Apply media queries from responsive value list.
242
242
  mbps = {
243
- media_query(bp): bp_value
244
- if isinstance(bp_value, dict)
245
- else {key: bp_value}
243
+ media_query(bp): (
244
+ bp_value if isinstance(bp_value, dict) else {key: bp_value}
245
+ )
246
246
  for bp, bp_value in enumerate(value)
247
247
  }
248
248
  if key.startswith("&:"):
reflex/testing.py CHANGED
@@ -223,7 +223,7 @@ class AppHarness:
223
223
  with chdir(self.app_path):
224
224
  reflex.reflex._init(
225
225
  name=self.app_name,
226
- template=reflex.constants.Templates.Kind.BLANK,
226
+ template=reflex.constants.Templates.DEFAULT,
227
227
  loglevel=reflex.constants.LogLevel.INFO,
228
228
  )
229
229
  self.app_module_path.write_text(source_code)
reflex/utils/console.py CHANGED
@@ -2,8 +2,6 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import List, Optional
6
-
7
5
  from rich.console import Console
8
6
  from rich.progress import MofNCompleteColumn, Progress, TimeElapsedColumn
9
7
  from rich.prompt import Prompt
@@ -150,7 +148,10 @@ def error(msg: str, **kwargs):
150
148
 
151
149
 
152
150
  def ask(
153
- question: str, choices: Optional[List[str]] = None, default: Optional[str] = None
151
+ question: str,
152
+ choices: list[str] | None = None,
153
+ default: str | None = None,
154
+ show_choices: bool = True,
154
155
  ) -> str:
155
156
  """Takes a prompt question and optionally a list of choices
156
157
  and returns the user input.
@@ -159,11 +160,12 @@ def ask(
159
160
  question: The question to ask the user.
160
161
  choices: A list of choices to select from.
161
162
  default: The default option selected.
163
+ show_choices: Whether to show the choices.
162
164
 
163
165
  Returns:
164
166
  A string with the user input.
165
167
  """
166
- return Prompt.ask(question, choices=choices, default=default) # type: ignore
168
+ return Prompt.ask(question, choices=choices, default=default, show_choices=show_choices) # type: ignore
167
169
 
168
170
 
169
171
  def progress():