reflex 0.6.8a2__py3-none-any.whl → 0.7.0a1__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 (154) hide show
  1. reflex/.templates/jinja/custom_components/pyproject.toml.jinja2 +1 -1
  2. reflex/.templates/jinja/web/pages/_app.js.jinja2 +7 -7
  3. reflex/.templates/jinja/web/pages/utils.js.jinja2 +2 -2
  4. reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js +1 -4
  5. reflex/.templates/web/utils/state.js +65 -36
  6. reflex/__init__.py +4 -17
  7. reflex/__init__.pyi +1 -2
  8. reflex/app.py +244 -109
  9. reflex/app_mixins/lifespan.py +9 -9
  10. reflex/app_mixins/middleware.py +6 -6
  11. reflex/app_module_for_backend.py +3 -7
  12. reflex/base.py +7 -7
  13. reflex/compiler/compiler.py +8 -0
  14. reflex/compiler/utils.py +35 -6
  15. reflex/components/base/bare.py +1 -1
  16. reflex/components/base/error_boundary.py +2 -1
  17. reflex/components/base/error_boundary.pyi +2 -1
  18. reflex/components/base/meta.py +2 -2
  19. reflex/components/base/strict_mode.py +10 -0
  20. reflex/components/base/strict_mode.pyi +57 -0
  21. reflex/components/component.py +38 -77
  22. reflex/components/core/banner.py +83 -4
  23. reflex/components/core/banner.pyi +86 -0
  24. reflex/components/core/breakpoints.py +3 -1
  25. reflex/components/core/client_side_routing.py +1 -1
  26. reflex/components/core/client_side_routing.pyi +1 -1
  27. reflex/components/core/cond.py +9 -10
  28. reflex/components/core/debounce.py +1 -1
  29. reflex/components/core/foreach.py +23 -3
  30. reflex/components/core/html.py +1 -1
  31. reflex/components/core/match.py +5 -5
  32. reflex/components/core/sticky.py +160 -0
  33. reflex/components/core/sticky.pyi +449 -0
  34. reflex/components/core/upload.py +2 -2
  35. reflex/components/datadisplay/code.py +5 -14
  36. reflex/components/datadisplay/dataeditor.py +7 -4
  37. reflex/components/datadisplay/logo.py +13 -8
  38. reflex/components/datadisplay/shiki_code_block.py +14 -9
  39. reflex/components/dynamic.py +22 -3
  40. reflex/components/el/constants/reflex.py +1 -1
  41. reflex/components/el/element.py +1 -1
  42. reflex/components/el/elements/forms.py +4 -4
  43. reflex/components/el/elements/forms.pyi +4 -4
  44. reflex/components/lucide/icon.py +46 -8
  45. reflex/components/lucide/icon.pyi +54 -0
  46. reflex/components/markdown/markdown.py +10 -8
  47. reflex/components/moment/moment.py +2 -2
  48. reflex/components/next/image.py +16 -4
  49. reflex/components/next/image.pyi +4 -2
  50. reflex/components/next/link.py +1 -1
  51. reflex/components/plotly/plotly.py +5 -5
  52. reflex/components/props.py +3 -3
  53. reflex/components/radix/__init__.pyi +1 -1
  54. reflex/components/radix/primitives/accordion.py +9 -5
  55. reflex/components/radix/primitives/accordion.pyi +3 -1
  56. reflex/components/radix/primitives/drawer.py +5 -2
  57. reflex/components/radix/primitives/drawer.pyi +4 -4
  58. reflex/components/radix/primitives/form.pyi +6 -6
  59. reflex/components/radix/primitives/progress.py +1 -1
  60. reflex/components/radix/primitives/slider.py +1 -1
  61. reflex/components/radix/themes/color_mode.py +11 -9
  62. reflex/components/radix/themes/components/alert_dialog.py +3 -0
  63. reflex/components/radix/themes/components/card.py +1 -1
  64. reflex/components/radix/themes/components/card.pyi +1 -1
  65. reflex/components/radix/themes/components/context_menu.py +5 -0
  66. reflex/components/radix/themes/components/dialog.py +3 -0
  67. reflex/components/radix/themes/components/dropdown_menu.py +5 -0
  68. reflex/components/radix/themes/components/hover_card.py +3 -0
  69. reflex/components/radix/themes/components/icon_button.py +2 -2
  70. reflex/components/radix/themes/components/icon_button.pyi +1 -0
  71. reflex/components/radix/themes/components/popover.py +3 -0
  72. reflex/components/radix/themes/components/radio_cards.py +2 -0
  73. reflex/components/radix/themes/components/radio_group.py +1 -1
  74. reflex/components/radix/themes/components/select.py +3 -0
  75. reflex/components/radix/themes/components/tabs.py +3 -0
  76. reflex/components/radix/themes/components/text_area.py +12 -0
  77. reflex/components/radix/themes/components/text_area.pyi +2 -0
  78. reflex/components/radix/themes/components/text_field.py +1 -1
  79. reflex/components/radix/themes/components/tooltip.py +3 -1
  80. reflex/components/radix/themes/components/tooltip.pyi +1 -0
  81. reflex/components/radix/themes/layout/__init__.pyi +1 -1
  82. reflex/components/radix/themes/layout/list.py +2 -2
  83. reflex/components/radix/themes/layout/stack.py +2 -2
  84. reflex/components/radix/themes/typography/link.py +1 -1
  85. reflex/components/radix/themes/typography/text.py +2 -2
  86. reflex/components/react_player/react_player.py +1 -1
  87. reflex/components/recharts/__init__.py +2 -0
  88. reflex/components/recharts/__init__.pyi +2 -0
  89. reflex/components/recharts/charts.py +15 -15
  90. reflex/components/recharts/general.py +19 -4
  91. reflex/components/recharts/general.pyi +55 -4
  92. reflex/components/recharts/polar.py +2 -2
  93. reflex/components/recharts/recharts.py +4 -4
  94. reflex/components/sonner/toast.py +15 -13
  95. reflex/components/sonner/toast.pyi +6 -6
  96. reflex/components/suneditor/editor.py +6 -4
  97. reflex/components/suneditor/editor.pyi +2 -2
  98. reflex/components/tags/iter_tag.py +3 -3
  99. reflex/components/tags/tag.py +25 -3
  100. reflex/config.py +48 -15
  101. reflex/constants/__init__.py +1 -0
  102. reflex/constants/base.py +4 -1
  103. reflex/constants/compiler.py +5 -2
  104. reflex/constants/config.py +8 -1
  105. reflex/constants/installer.py +9 -9
  106. reflex/constants/style.py +1 -1
  107. reflex/custom_components/custom_components.py +9 -7
  108. reflex/event.py +130 -161
  109. reflex/experimental/__init__.py +19 -11
  110. reflex/experimental/client_state.py +53 -28
  111. reflex/experimental/hooks.py +5 -5
  112. reflex/experimental/layout.py +8 -5
  113. reflex/experimental/layout.pyi +1 -1
  114. reflex/experimental/misc.py +3 -3
  115. reflex/istate/wrappers.py +1 -1
  116. reflex/middleware/hydrate_middleware.py +2 -2
  117. reflex/model.py +11 -6
  118. reflex/page.py +3 -3
  119. reflex/reflex.py +90 -19
  120. reflex/route.py +1 -1
  121. reflex/state.py +358 -401
  122. reflex/style.py +27 -3
  123. reflex/testing.py +29 -23
  124. reflex/utils/build.py +6 -2
  125. reflex/utils/codespaces.py +1 -4
  126. reflex/utils/compat.py +6 -5
  127. reflex/utils/console.py +52 -16
  128. reflex/utils/exceptions.py +76 -26
  129. reflex/utils/exec.py +69 -74
  130. reflex/utils/export.py +6 -1
  131. reflex/utils/format.py +7 -39
  132. reflex/utils/imports.py +2 -2
  133. reflex/utils/lazy_loader.py +7 -1
  134. reflex/utils/path_ops.py +28 -14
  135. reflex/utils/prerequisites.py +324 -65
  136. reflex/utils/processes.py +45 -32
  137. reflex/utils/pyi_generator.py +30 -25
  138. reflex/utils/registry.py +4 -4
  139. reflex/utils/serializers.py +1 -1
  140. reflex/utils/telemetry.py +5 -4
  141. reflex/utils/types.py +42 -18
  142. reflex/vars/base.py +650 -333
  143. reflex/vars/datetime.py +6 -7
  144. reflex/vars/dep_tracking.py +344 -0
  145. reflex/vars/function.py +11 -5
  146. reflex/vars/number.py +31 -43
  147. reflex/vars/object.py +63 -62
  148. reflex/vars/sequence.py +79 -67
  149. {reflex-0.6.8a2.dist-info → reflex-0.7.0a1.dist-info}/METADATA +7 -8
  150. {reflex-0.6.8a2.dist-info → reflex-0.7.0a1.dist-info}/RECORD +153 -149
  151. {reflex-0.6.8a2.dist-info → reflex-0.7.0a1.dist-info}/WHEEL +1 -1
  152. reflex/experimental/assets.py +0 -37
  153. {reflex-0.6.8a2.dist-info → reflex-0.7.0a1.dist-info}/LICENSE +0 -0
  154. {reflex-0.6.8a2.dist-info → reflex-0.7.0a1.dist-info}/entry_points.txt +0 -0
reflex/utils/processes.py CHANGED
@@ -15,12 +15,14 @@ from typing import Callable, Generator, List, Optional, Tuple, Union
15
15
  import psutil
16
16
  import typer
17
17
  from redis.exceptions import RedisError
18
+ from rich.progress import Progress
18
19
 
19
20
  from reflex import constants
21
+ from reflex.config import environment
20
22
  from reflex.utils import console, path_ops, prerequisites
21
23
 
22
24
 
23
- def kill(pid):
25
+ def kill(pid: int):
24
26
  """Kill a process.
25
27
 
26
28
  Args:
@@ -48,7 +50,7 @@ def get_num_workers() -> int:
48
50
  return (os.cpu_count() or 1) * 2 + 1
49
51
 
50
52
 
51
- def get_process_on_port(port) -> Optional[psutil.Process]:
53
+ def get_process_on_port(port: int) -> Optional[psutil.Process]:
52
54
  """Get the process on the given port.
53
55
 
54
56
  Args:
@@ -62,7 +64,7 @@ def get_process_on_port(port) -> Optional[psutil.Process]:
62
64
  psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess
63
65
  ):
64
66
  if importlib.metadata.version("psutil") >= "6.0.0":
65
- conns = proc.net_connections(kind="inet") # type: ignore
67
+ conns = proc.net_connections(kind="inet")
66
68
  else:
67
69
  conns = proc.connections(kind="inet")
68
70
  for conn in conns:
@@ -71,7 +73,7 @@ def get_process_on_port(port) -> Optional[psutil.Process]:
71
73
  return None
72
74
 
73
75
 
74
- def is_process_on_port(port) -> bool:
76
+ def is_process_on_port(port: int) -> bool:
75
77
  """Check if a process is running on the given port.
76
78
 
77
79
  Args:
@@ -83,7 +85,7 @@ def is_process_on_port(port) -> bool:
83
85
  return get_process_on_port(port) is not None
84
86
 
85
87
 
86
- def kill_process_on_port(port):
88
+ def kill_process_on_port(port: int):
87
89
  """Kill the process on the given port.
88
90
 
89
91
  Args:
@@ -91,10 +93,10 @@ def kill_process_on_port(port):
91
93
  """
92
94
  if get_process_on_port(port) is not None:
93
95
  with contextlib.suppress(psutil.AccessDenied):
94
- get_process_on_port(port).kill() # type: ignore
96
+ get_process_on_port(port).kill() # pyright: ignore [reportOptionalMemberAccess]
95
97
 
96
98
 
97
- def change_port(port: str, _type: str) -> str:
99
+ def change_port(port: int, _type: str) -> int:
98
100
  """Change the port.
99
101
 
100
102
  Args:
@@ -105,7 +107,7 @@ def change_port(port: str, _type: str) -> str:
105
107
  The new port.
106
108
 
107
109
  """
108
- new_port = str(int(port) + 1)
110
+ new_port = port + 1
109
111
  if is_process_on_port(new_port):
110
112
  return change_port(new_port, _type)
111
113
  console.info(
@@ -114,7 +116,7 @@ def change_port(port: str, _type: str) -> str:
114
116
  return new_port
115
117
 
116
118
 
117
- def handle_port(service_name: str, port: str, default_port: str) -> str:
119
+ def handle_port(service_name: str, port: int, default_port: int) -> int:
118
120
  """Change port if the specified port is in use and is not explicitly specified as a CLI arg or config arg.
119
121
  otherwise tell the user the port is in use and exit the app.
120
122
 
@@ -133,7 +135,7 @@ def handle_port(service_name: str, port: str, default_port: str) -> str:
133
135
  Exit:when the port is in use.
134
136
  """
135
137
  if is_process_on_port(port):
136
- if int(port) == int(default_port):
138
+ if port == int(default_port):
137
139
  return change_port(port, service_name)
138
140
  else:
139
141
  console.error(f"{service_name.capitalize()} port: {port} is already in use")
@@ -141,7 +143,12 @@ def handle_port(service_name: str, port: str, default_port: str) -> str:
141
143
  return port
142
144
 
143
145
 
144
- def new_process(args, run: bool = False, show_logs: bool = False, **kwargs):
146
+ def new_process(
147
+ args: str | list[str] | list[str | None] | list[str | Path | None],
148
+ run: bool = False,
149
+ show_logs: bool = False,
150
+ **kwargs,
151
+ ):
145
152
  """Wrapper over subprocess.Popen to unify the launch of child processes.
146
153
 
147
154
  Args:
@@ -156,24 +163,30 @@ def new_process(args, run: bool = False, show_logs: bool = False, **kwargs):
156
163
  Raises:
157
164
  Exit: When attempting to run a command with a None value.
158
165
  """
159
- node_bin_path = str(path_ops.get_node_bin_path())
160
- if not node_bin_path and not prerequisites.CURRENTLY_INSTALLING_NODE:
161
- console.warn(
162
- "The path to the Node binary could not be found. Please ensure that Node is properly "
163
- "installed and added to your system's PATH environment variable or try running "
164
- "`reflex init` again."
165
- )
166
- if None in args:
166
+ # Check for invalid command first.
167
+ if isinstance(args, list) and None in args:
167
168
  console.error(f"Invalid command: {args}")
168
169
  raise typer.Exit(1)
169
- # Add the node bin path to the PATH environment variable.
170
+
171
+ path_env: str = os.environ.get("PATH", "")
172
+
173
+ # Add node_bin_path to the PATH environment variable.
174
+ if not environment.REFLEX_BACKEND_ONLY.get():
175
+ node_bin_path = str(path_ops.get_node_bin_path())
176
+ if not node_bin_path and not prerequisites.CURRENTLY_INSTALLING_NODE:
177
+ console.warn(
178
+ "The path to the Node binary could not be found. Please ensure that Node is properly "
179
+ "installed and added to your system's PATH environment variable or try running "
180
+ "`reflex init` again."
181
+ )
182
+ path_env = os.pathsep.join([node_bin_path, path_env])
183
+
170
184
  env: dict[str, str] = {
171
185
  **os.environ,
172
- "PATH": os.pathsep.join(
173
- [node_bin_path if node_bin_path else "", os.environ["PATH"]]
174
- ), # type: ignore
186
+ "PATH": path_env,
175
187
  **kwargs.pop("env", {}),
176
188
  }
189
+
177
190
  kwargs = {
178
191
  "env": env,
179
192
  "stderr": None if show_logs else subprocess.STDOUT,
@@ -185,7 +198,7 @@ def new_process(args, run: bool = False, show_logs: bool = False, **kwargs):
185
198
  }
186
199
  console.debug(f"Running command: {args}")
187
200
  fn = subprocess.run if run else subprocess.Popen
188
- return fn(args, **kwargs)
201
+ return fn(args, **kwargs) # pyright: ignore [reportCallIssue, reportArgumentType]
189
202
 
190
203
 
191
204
  @contextlib.contextmanager
@@ -206,14 +219,14 @@ def run_concurrently_context(
206
219
  return
207
220
 
208
221
  # Convert the functions to tuples.
209
- fns = [fn if isinstance(fn, tuple) else (fn,) for fn in fns] # type: ignore
222
+ fns = [fn if isinstance(fn, tuple) else (fn,) for fn in fns] # pyright: ignore [reportAssignmentType]
210
223
 
211
224
  # Run the functions concurrently.
212
225
  executor = None
213
226
  try:
214
227
  executor = futures.ThreadPoolExecutor(max_workers=len(fns))
215
228
  # Submit the tasks.
216
- tasks = [executor.submit(*fn) for fn in fns] # type: ignore
229
+ tasks = [executor.submit(*fn) for fn in fns] # pyright: ignore [reportArgumentType]
217
230
 
218
231
  # Yield control back to the main thread while tasks are running.
219
232
  yield tasks
@@ -241,7 +254,7 @@ def run_concurrently(*fns: Union[Callable, Tuple]) -> None:
241
254
  def stream_logs(
242
255
  message: str,
243
256
  process: subprocess.Popen,
244
- progress=None,
257
+ progress: Progress | None = None,
245
258
  suppress_errors: bool = False,
246
259
  analytics_enabled: bool = False,
247
260
  ):
@@ -361,7 +374,7 @@ def get_command_with_loglevel(command: list[str]) -> list[str]:
361
374
  The updated command list
362
375
  """
363
376
  npm_path = path_ops.get_npm_path()
364
- npm_path = str(Path(npm_path).resolve()) if npm_path else npm_path
377
+ npm_path = str(npm_path) if npm_path else None
365
378
 
366
379
  if command[0] == npm_path:
367
380
  return [*command, "--loglevel", "silly"]
@@ -369,10 +382,10 @@ def get_command_with_loglevel(command: list[str]) -> list[str]:
369
382
 
370
383
 
371
384
  def run_process_with_fallback(
372
- args,
385
+ args: list[str],
373
386
  *,
374
- show_status_message,
375
- fallback=None,
387
+ show_status_message: str,
388
+ fallback: str | list | None = None,
376
389
  analytics_enabled: bool = False,
377
390
  **kwargs,
378
391
  ):
@@ -411,7 +424,7 @@ def run_process_with_fallback(
411
424
  )
412
425
 
413
426
 
414
- def execute_command_and_return_output(command) -> str | None:
427
+ def execute_command_and_return_output(command: str) -> str | None:
415
428
  """Execute a command and return the output.
416
429
 
417
430
  Args:
@@ -83,7 +83,7 @@ DEFAULT_IMPORTS = {
83
83
  }
84
84
 
85
85
 
86
- def _walk_files(path):
86
+ def _walk_files(path: str | Path):
87
87
  """Walk all files in a path.
88
88
  This can be replaced with Path.walk() in python3.12.
89
89
 
@@ -114,7 +114,9 @@ def _relative_to_pwd(path: Path) -> Path:
114
114
  return path
115
115
 
116
116
 
117
- def _get_type_hint(value, type_hint_globals, is_optional=True) -> str:
117
+ def _get_type_hint(
118
+ value: Any, type_hint_globals: dict, is_optional: bool = True
119
+ ) -> str:
118
120
  """Resolve the type hint for value.
119
121
 
120
122
  Args:
@@ -229,7 +231,7 @@ def _generate_imports(
229
231
  """
230
232
  return [
231
233
  *[
232
- ast.ImportFrom(module=name, names=[ast.alias(name=val) for val in values])
234
+ ast.ImportFrom(module=name, names=[ast.alias(name=val) for val in values]) # pyright: ignore [reportCallIssue]
233
235
  for name, values in DEFAULT_IMPORTS.items()
234
236
  ],
235
237
  ast.Import([ast.alias("reflex")]),
@@ -367,7 +369,7 @@ def _extract_class_props_as_ast_nodes(
367
369
  # Try to get default from pydantic field definition.
368
370
  default = target_class.__fields__[name].default
369
371
  if isinstance(default, Var):
370
- default = default._decode() # type: ignore
372
+ default = default._decode()
371
373
 
372
374
  kwargs.append(
373
375
  (
@@ -383,7 +385,7 @@ def _extract_class_props_as_ast_nodes(
383
385
  return kwargs
384
386
 
385
387
 
386
- def type_to_ast(typ, cls: type) -> ast.AST:
388
+ def type_to_ast(typ: Any, cls: type) -> ast.AST:
387
389
  """Converts any type annotation into its AST representation.
388
390
  Handles nested generic types, unions, etc.
389
391
 
@@ -434,14 +436,16 @@ def type_to_ast(typ, cls: type) -> ast.AST:
434
436
  if len(arg_nodes) == 1:
435
437
  slice_value = arg_nodes[0]
436
438
  else:
437
- slice_value = ast.Tuple(elts=arg_nodes, ctx=ast.Load())
439
+ slice_value = ast.Tuple(elts=arg_nodes, ctx=ast.Load()) # pyright: ignore [reportArgumentType]
438
440
 
439
441
  return ast.Subscript(
440
- value=ast.Name(id=base_name), slice=ast.Index(value=slice_value), ctx=ast.Load()
442
+ value=ast.Name(id=base_name),
443
+ slice=ast.Index(value=slice_value), # pyright: ignore [reportArgumentType]
444
+ ctx=ast.Load(),
441
445
  )
442
446
 
443
447
 
444
- def _get_parent_imports(func):
448
+ def _get_parent_imports(func: Callable):
445
449
  _imports = {"reflex.vars": ["Var"]}
446
450
  for type_hint in inspect.get_annotations(func).values():
447
451
  try:
@@ -575,7 +579,7 @@ def _generate_component_create_functiondef(
575
579
  arg=trigger,
576
580
  annotation=ast.Subscript(
577
581
  ast.Name("Optional"),
578
- ast.Index( # type: ignore
582
+ ast.Index( # pyright: ignore [reportArgumentType]
579
583
  value=ast.Name(
580
584
  id=ast.unparse(
581
585
  figure_out_return_type(
@@ -618,10 +622,10 @@ def _generate_component_create_functiondef(
618
622
  defaults=[],
619
623
  )
620
624
 
621
- definition = ast.FunctionDef(
625
+ definition = ast.FunctionDef( # pyright: ignore [reportCallIssue]
622
626
  name="create",
623
627
  args=create_args,
624
- body=[
628
+ body=[ # pyright: ignore [reportArgumentType]
625
629
  ast.Expr(
626
630
  value=ast.Constant(
627
631
  value=_generate_docstrings(
@@ -630,7 +634,7 @@ def _generate_component_create_functiondef(
630
634
  ),
631
635
  ),
632
636
  ast.Expr(
633
- value=ast.Ellipsis(),
637
+ value=ast.Constant(value=Ellipsis),
634
638
  ),
635
639
  ],
636
640
  decorator_list=[
@@ -641,7 +645,7 @@ def _generate_component_create_functiondef(
641
645
  else [ast.Name(id="classmethod")]
642
646
  ),
643
647
  ],
644
- lineno=node.lineno if node is not None else None,
648
+ lineno=node.lineno if node is not None else None, # pyright: ignore [reportArgumentType]
645
649
  returns=ast.Constant(value=clz.__name__),
646
650
  )
647
651
  return definition
@@ -680,7 +684,7 @@ def _generate_staticmethod_call_functiondef(
680
684
  else []
681
685
  ),
682
686
  )
683
- definition = ast.FunctionDef(
687
+ definition = ast.FunctionDef( # pyright: ignore [reportCallIssue]
684
688
  name="__call__",
685
689
  args=call_args,
686
690
  body=[
@@ -690,11 +694,12 @@ def _generate_staticmethod_call_functiondef(
690
694
  ),
691
695
  ],
692
696
  decorator_list=[ast.Name(id="staticmethod")],
693
- lineno=node.lineno if node is not None else None,
697
+ lineno=node.lineno if node is not None else None, # pyright: ignore [reportArgumentType]
694
698
  returns=ast.Constant(
695
699
  value=_get_type_hint(
696
700
  typing.get_type_hints(clz.__call__).get("return", None),
697
701
  type_hint_globals,
702
+ is_optional=False,
698
703
  )
699
704
  ),
700
705
  )
@@ -726,17 +731,17 @@ def _generate_namespace_call_functiondef(
726
731
  clz = classes[clz_name]
727
732
 
728
733
  if not hasattr(clz.__call__, "__self__"):
729
- return _generate_staticmethod_call_functiondef(node, clz, type_hint_globals) # type: ignore
734
+ return _generate_staticmethod_call_functiondef(node, clz, type_hint_globals) # pyright: ignore [reportArgumentType]
730
735
 
731
736
  # Determine which class is wrapped by the namespace __call__ method
732
737
  component_clz = clz.__call__.__self__
733
738
 
734
- if clz.__call__.__func__.__name__ != "create":
739
+ if clz.__call__.__func__.__name__ != "create": # pyright: ignore [reportFunctionMemberAccess]
735
740
  return None
736
741
 
737
742
  definition = _generate_component_create_functiondef(
738
743
  node=None,
739
- clz=component_clz, # type: ignore
744
+ clz=component_clz, # pyright: ignore [reportArgumentType]
740
745
  type_hint_globals=type_hint_globals,
741
746
  )
742
747
  definition.name = "__call__"
@@ -816,7 +821,7 @@ class StubGenerator(ast.NodeTransformer):
816
821
  The modified Module node.
817
822
  """
818
823
  self.generic_visit(node)
819
- return self._remove_docstring(node) # type: ignore
824
+ return self._remove_docstring(node) # pyright: ignore [reportReturnType]
820
825
 
821
826
  def visit_Import(
822
827
  self, node: ast.Import | ast.ImportFrom
@@ -914,7 +919,7 @@ class StubGenerator(ast.NodeTransformer):
914
919
  node.body.append(call_definition)
915
920
  if not node.body:
916
921
  # We should never return an empty body.
917
- node.body.append(ast.Expr(value=ast.Ellipsis()))
922
+ node.body.append(ast.Expr(value=ast.Constant(value=Ellipsis)))
918
923
  self.current_class = None
919
924
  return node
920
925
 
@@ -941,9 +946,9 @@ class StubGenerator(ast.NodeTransformer):
941
946
  if node.name.startswith("_") and node.name != "__call__":
942
947
  return None # remove private methods
943
948
 
944
- if node.body[-1] != ast.Expr(value=ast.Ellipsis()):
949
+ if node.body[-1] != ast.Expr(value=ast.Constant(value=Ellipsis)):
945
950
  # Blank out the function body for public functions.
946
- node.body = [ast.Expr(value=ast.Ellipsis())]
951
+ node.body = [ast.Expr(value=ast.Constant(value=Ellipsis))]
947
952
  return node
948
953
 
949
954
  def visit_Assign(self, node: ast.Assign) -> ast.Assign | None:
@@ -1050,7 +1055,7 @@ class PyiGenerator:
1050
1055
  pyi_path.write_text(pyi_content)
1051
1056
  logger.info(f"Wrote {relpath}")
1052
1057
 
1053
- def _get_init_lazy_imports(self, mod, new_tree):
1058
+ def _get_init_lazy_imports(self, mod: tuple | ModuleType, new_tree: ast.AST):
1054
1059
  # retrieve the _SUBMODULES and _SUBMOD_ATTRS from an init file if present.
1055
1060
  sub_mods = getattr(mod, "_SUBMODULES", None)
1056
1061
  sub_mod_attrs = getattr(mod, "_SUBMOD_ATTRS", None)
@@ -1077,7 +1082,7 @@ class PyiGenerator:
1077
1082
  + (
1078
1083
  " # type: ignore"
1079
1084
  if mod in pyright_ignore_imports
1080
- else " # noqa" # ignore ruff formatting here for cases like rx.list.
1085
+ else " # noqa: F401" # ignore ruff formatting here for cases like rx.list.
1081
1086
  if isinstance(mod, tuple)
1082
1087
  else ""
1083
1088
  )
@@ -1136,7 +1141,7 @@ class PyiGenerator:
1136
1141
  if pyi_path:
1137
1142
  self.written_files.append(pyi_path)
1138
1143
 
1139
- def scan_all(self, targets, changed_files: list[Path] | None = None):
1144
+ def scan_all(self, targets: list, changed_files: list[Path] | None = None):
1140
1145
  """Scan all targets for class inheriting Component and generate the .pyi files.
1141
1146
 
1142
1147
  Args:
reflex/utils/registry.py CHANGED
@@ -22,15 +22,15 @@ def latency(registry: str) -> int:
22
22
  return 10_000_000
23
23
 
24
24
 
25
- def average_latency(registry, attempts: int = 3) -> int:
25
+ def average_latency(registry: str, attempts: int = 3) -> int:
26
26
  """Get the average latency of a registry.
27
27
 
28
28
  Args:
29
- registry (str): The URL of the registry.
30
- attempts (int): The number of attempts to make. Defaults to 10.
29
+ registry: The URL of the registry.
30
+ attempts: The number of attempts to make. Defaults to 10.
31
31
 
32
32
  Returns:
33
- int: The average latency of the registry in microseconds.
33
+ The average latency of the registry in microseconds.
34
34
  """
35
35
  return sum(latency(registry) for _ in range(attempts)) // attempts
36
36
 
@@ -476,7 +476,7 @@ try:
476
476
  base64_image = base64.b64encode(image_bytes).decode("utf-8")
477
477
  try:
478
478
  # Newer method to get the mime type, but does not always work.
479
- mime_type = image.get_format_mimetype() # type: ignore
479
+ mime_type = image.get_format_mimetype() # pyright: ignore [reportAttributeAccessIssue]
480
480
  except AttributeError:
481
481
  try:
482
482
  # Fallback method
reflex/utils/telemetry.py CHANGED
@@ -122,7 +122,7 @@ def _prepare_event(event: str, **kwargs) -> dict:
122
122
  return {}
123
123
 
124
124
  if UTC is None:
125
- # for python 3.9 & 3.10
125
+ # for python 3.10
126
126
  stamp = datetime.utcnow().isoformat()
127
127
  else:
128
128
  # for python 3.11 & 3.12
@@ -156,12 +156,13 @@ def _prepare_event(event: str, **kwargs) -> dict:
156
156
  def _send_event(event_data: dict) -> bool:
157
157
  try:
158
158
  httpx.post(POSTHOG_API_URL, json=event_data)
159
- return True
160
159
  except Exception:
161
160
  return False
161
+ else:
162
+ return True
162
163
 
163
164
 
164
- def _send(event, telemetry_enabled, **kwargs):
165
+ def _send(event: str, telemetry_enabled: bool | None, **kwargs):
165
166
  from reflex.config import get_config
166
167
 
167
168
  # Get the telemetry_enabled from the config if it is not specified.
@@ -188,7 +189,7 @@ def send(event: str, telemetry_enabled: bool | None = None, **kwargs):
188
189
  kwargs: Additional data to send with the event.
189
190
  """
190
191
 
191
- async def async_send(event, telemetry_enabled, **kwargs):
192
+ async def async_send(event: str, telemetry_enabled: bool | None, **kwargs):
192
193
  return _send(event, telemetry_enabled, **kwargs)
193
194
 
194
195
  try:
reflex/utils/types.py CHANGED
@@ -24,7 +24,7 @@ from typing import (
24
24
  Tuple,
25
25
  Type,
26
26
  Union,
27
- _GenericAlias, # type: ignore
27
+ _GenericAlias, # pyright: ignore [reportAttributeAccessIssue]
28
28
  get_args,
29
29
  get_type_hints,
30
30
  )
@@ -39,7 +39,9 @@ from reflex.components.core.breakpoints import Breakpoints
39
39
  try:
40
40
  from pydantic.v1.fields import ModelField
41
41
  except ModuleNotFoundError:
42
- from pydantic.fields import ModelField # type: ignore
42
+ from pydantic.fields import (
43
+ ModelField, # pyright: ignore [reportAttributeAccessIssue]
44
+ )
43
45
 
44
46
  from sqlalchemy.ext.associationproxy import AssociationProxyInstance
45
47
  from sqlalchemy.ext.hybrid import hybrid_property
@@ -70,13 +72,15 @@ GenericAliasTypes = [_GenericAlias]
70
72
 
71
73
  with contextlib.suppress(ImportError):
72
74
  # For newer versions of Python.
73
- from types import GenericAlias # type: ignore
75
+ from types import GenericAlias
74
76
 
75
77
  GenericAliasTypes.append(GenericAlias)
76
78
 
77
79
  with contextlib.suppress(ImportError):
78
80
  # For older versions of Python.
79
- from typing import _SpecialGenericAlias # type: ignore
81
+ from typing import (
82
+ _SpecialGenericAlias, # pyright: ignore [reportAttributeAccessIssue]
83
+ )
80
84
 
81
85
  GenericAliasTypes.append(_SpecialGenericAlias)
82
86
 
@@ -153,7 +157,7 @@ class Unset:
153
157
 
154
158
 
155
159
  @lru_cache()
156
- def get_origin(tp):
160
+ def get_origin(tp: Any):
157
161
  """Get the origin of a class.
158
162
 
159
163
  Args:
@@ -175,7 +179,7 @@ def is_generic_alias(cls: GenericType) -> bool:
175
179
  Returns:
176
180
  Whether the class is a generic alias.
177
181
  """
178
- return isinstance(cls, GenericAliasTypes)
182
+ return isinstance(cls, GenericAliasTypes) # pyright: ignore [reportArgumentType]
179
183
 
180
184
 
181
185
  def unionize(*args: GenericType) -> Type:
@@ -188,14 +192,14 @@ def unionize(*args: GenericType) -> Type:
188
192
  The unionized types.
189
193
  """
190
194
  if not args:
191
- return Any
195
+ return Any # pyright: ignore [reportReturnType]
192
196
  if len(args) == 1:
193
197
  return args[0]
194
198
  # We are bisecting the args list here to avoid hitting the recursion limit
195
199
  # In Python versions >= 3.11, we can simply do `return Union[*args]`
196
200
  midpoint = len(args) // 2
197
201
  first_half, second_half = args[:midpoint], args[midpoint:]
198
- return Union[unionize(*first_half), unionize(*second_half)]
202
+ return Union[unionize(*first_half), unionize(*second_half)] # pyright: ignore [reportReturnType]
199
203
 
200
204
 
201
205
  def is_none(cls: GenericType) -> bool:
@@ -236,7 +240,7 @@ def is_literal(cls: GenericType) -> bool:
236
240
  return get_origin(cls) is Literal
237
241
 
238
242
 
239
- def has_args(cls) -> bool:
243
+ def has_args(cls: Type) -> bool:
240
244
  """Check if the class has generic parameters.
241
245
 
242
246
  Args:
@@ -351,13 +355,13 @@ def get_attribute_access_type(cls: GenericType, name: str) -> GenericType | None
351
355
  if type_ is not None:
352
356
  if hasattr(column_type, "item_type"):
353
357
  try:
354
- item_type = column_type.item_type.python_type # type: ignore
358
+ item_type = column_type.item_type.python_type # pyright: ignore [reportAttributeAccessIssue]
355
359
  except NotImplementedError:
356
360
  item_type = None
357
361
  if item_type is not None:
358
362
  if type_ in PrimitiveToAnnotation:
359
- type_ = PrimitiveToAnnotation[type_] # type: ignore
360
- type_ = type_[item_type] # type: ignore
363
+ type_ = PrimitiveToAnnotation[type_]
364
+ type_ = type_[item_type] # pyright: ignore [reportIndexIssue]
361
365
  if column.nullable:
362
366
  type_ = Optional[type_]
363
367
  return type_
@@ -432,7 +436,7 @@ def get_base_class(cls: GenericType) -> Type:
432
436
  return type(get_args(cls)[0])
433
437
 
434
438
  if is_union(cls):
435
- return tuple(get_base_class(arg) for arg in get_args(cls))
439
+ return tuple(get_base_class(arg) for arg in get_args(cls)) # pyright: ignore [reportReturnType]
436
440
 
437
441
  return get_base_class(cls.__origin__) if is_generic_alias(cls) else cls
438
442
 
@@ -605,7 +609,9 @@ def _isinstance(obj: Any, cls: GenericType, nested: bool = False) -> bool:
605
609
  return (
606
610
  isinstance(obj, tuple)
607
611
  and len(obj) == len(args)
608
- and all(_isinstance(item, arg) for item, arg in zip(obj, args))
612
+ and all(
613
+ _isinstance(item, arg) for item, arg in zip(obj, args, strict=True)
614
+ )
609
615
  )
610
616
  if origin in (dict, Breakpoints):
611
617
  return isinstance(obj, dict) and all(
@@ -747,7 +753,7 @@ def check_prop_in_allowed_types(prop: Any, allowed_types: Iterable) -> bool:
747
753
  return type_ in allowed_types
748
754
 
749
755
 
750
- def is_encoded_fstring(value) -> bool:
756
+ def is_encoded_fstring(value: Any) -> bool:
751
757
  """Check if a value is an encoded Var f-string.
752
758
 
753
759
  Args:
@@ -790,7 +796,7 @@ def validate_literal(key: str, value: Any, expected_type: Type, comp_name: str):
790
796
  )
791
797
 
792
798
 
793
- def validate_parameter_literals(func):
799
+ def validate_parameter_literals(func: Callable):
794
800
  """Decorator to check that the arguments passed to a function
795
801
  correspond to the correct function parameter if it (the parameter)
796
802
  is a literal type.
@@ -808,7 +814,7 @@ def validate_parameter_literals(func):
808
814
  annotations = {param[0]: param[1].annotation for param in func_params}
809
815
 
810
816
  # validate args
811
- for param, arg in zip(annotations, args):
817
+ for param, arg in zip(annotations, args, strict=False):
812
818
  if annotations[param] is inspect.Parameter.empty:
813
819
  continue
814
820
  validate_literal(param, arg, annotations[param], func.__name__)
@@ -829,6 +835,22 @@ StateBases = get_base_class(StateVar)
829
835
  StateIterBases = get_base_class(StateIterVar)
830
836
 
831
837
 
838
+ def safe_issubclass(cls: Type, cls_check: Type | Tuple[Type, ...]):
839
+ """Check if a class is a subclass of another class. Returns False if internal error occurs.
840
+
841
+ Args:
842
+ cls: The class to check.
843
+ cls_check: The class to check against.
844
+
845
+ Returns:
846
+ Whether the class is a subclass of the other class.
847
+ """
848
+ try:
849
+ return issubclass(cls, cls_check)
850
+ except TypeError:
851
+ return False
852
+
853
+
832
854
  def typehint_issubclass(possible_subclass: Any, possible_superclass: Any) -> bool:
833
855
  """Check if a type hint is a subclass of another type hint.
834
856
 
@@ -890,6 +912,8 @@ def typehint_issubclass(possible_subclass: Any, possible_superclass: Any) -> boo
890
912
  # It also ignores when the length of the arguments is different
891
913
  return all(
892
914
  typehint_issubclass(provided_arg, accepted_arg)
893
- for provided_arg, accepted_arg in zip(provided_args, accepted_args)
915
+ for provided_arg, accepted_arg in zip(
916
+ provided_args, accepted_args, strict=False
917
+ )
894
918
  if accepted_arg is not Any
895
919
  )