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/config.py CHANGED
@@ -12,6 +12,7 @@ import threading
12
12
  import urllib.parse
13
13
  from importlib.util import find_spec
14
14
  from pathlib import Path
15
+ from types import ModuleType
15
16
  from typing import (
16
17
  TYPE_CHECKING,
17
18
  Any,
@@ -389,7 +390,7 @@ class EnvVar(Generic[T]):
389
390
  os.environ[self.name] = str(value)
390
391
 
391
392
 
392
- class env_var: # type: ignore
393
+ class env_var: # noqa: N801 # pyright: ignore [reportRedeclaration]
393
394
  """Descriptor for environment variables."""
394
395
 
395
396
  name: str
@@ -406,7 +407,7 @@ class env_var: # type: ignore
406
407
  self.default = default
407
408
  self.internal = internal
408
409
 
409
- def __set_name__(self, owner, name):
410
+ def __set_name__(self, owner: Any, name: str):
410
411
  """Set the name of the descriptor.
411
412
 
412
413
  Args:
@@ -415,7 +416,7 @@ class env_var: # type: ignore
415
416
  """
416
417
  self.name = name
417
418
 
418
- def __get__(self, instance, owner):
419
+ def __get__(self, instance: Any, owner: Any):
419
420
  """Get the EnvVar instance.
420
421
 
421
422
  Args:
@@ -434,7 +435,7 @@ class env_var: # type: ignore
434
435
 
435
436
  if TYPE_CHECKING:
436
437
 
437
- def env_var(default, internal=False) -> EnvVar:
438
+ def env_var(default: Any, internal: bool = False) -> EnvVar:
438
439
  """Typing helper for the env_var descriptor.
439
440
 
440
441
  Args:
@@ -489,6 +490,9 @@ class EnvironmentVariables:
489
490
  # The working directory for the next.js commands.
490
491
  REFLEX_WEB_WORKDIR: EnvVar[Path] = env_var(Path(constants.Dirs.WEB))
491
492
 
493
+ # The working directory for the states directory.
494
+ REFLEX_STATES_WORKDIR: EnvVar[Path] = env_var(Path(constants.Dirs.STATES))
495
+
492
496
  # Path to the alembic config file
493
497
  ALEMBIC_CONFIG: EnvVar[ExistingPath] = env_var(Path(constants.ALEMBIC_CONFIG))
494
498
 
@@ -555,9 +559,6 @@ class EnvironmentVariables:
555
559
  # Arguments to pass to the app harness driver.
556
560
  APP_HARNESS_DRIVER_ARGS: EnvVar[str] = env_var("")
557
561
 
558
- # Where to save screenshots when tests fail.
559
- SCREENSHOT_DIR: EnvVar[Optional[Path]] = env_var(None)
560
-
561
562
  # Whether to check for outdated package versions.
562
563
  REFLEX_CHECK_LATEST_VERSION: EnvVar[bool] = env_var(True)
563
564
 
@@ -567,6 +568,9 @@ class EnvironmentVariables:
567
568
  # The maximum size of the reflex state in kilobytes.
568
569
  REFLEX_STATE_SIZE_LIMIT: EnvVar[int] = env_var(1000)
569
570
 
571
+ # Whether to use the turbopack bundler.
572
+ REFLEX_USE_TURBOPACK: EnvVar[bool] = env_var(True)
573
+
570
574
 
571
575
  environment = EnvironmentVariables()
572
576
 
@@ -596,7 +600,7 @@ class Config(Base):
596
600
  See the [configuration](https://reflex.dev/docs/getting-started/configuration/) docs for more info.
597
601
  """
598
602
 
599
- class Config:
603
+ class Config: # pyright: ignore [reportIncompatibleVariableOverride]
600
604
  """Pydantic config for the config."""
601
605
 
602
606
  validate_assignment = True
@@ -604,6 +608,9 @@ class Config(Base):
604
608
  # The name of the app (should match the name of the app directory).
605
609
  app_name: str
606
610
 
611
+ # The path to the app module.
612
+ app_module_import: Optional[str] = None
613
+
607
614
  # The log level to use.
608
615
  loglevel: constants.LogLevel = constants.LogLevel.DEFAULT
609
616
 
@@ -696,6 +703,12 @@ class Config(Base):
696
703
  # Path to file containing key-values pairs to override in the environment; Dotenv format.
697
704
  env_file: Optional[str] = None
698
705
 
706
+ # Whether to display the sticky "Built with Reflex" badge on all pages.
707
+ show_built_with_reflex: bool = True
708
+
709
+ # Whether the app is running in the reflex cloud environment.
710
+ is_reflex_cloud: bool = False
711
+
699
712
  def __init__(self, *args, **kwargs):
700
713
  """Initialize the config values.
701
714
 
@@ -726,6 +739,19 @@ class Config(Base):
726
739
  "REDIS_URL is required when using the redis state manager."
727
740
  )
728
741
 
742
+ @property
743
+ def app_module(self) -> ModuleType | None:
744
+ """Return the app module if `app_module_import` is set.
745
+
746
+ Returns:
747
+ The app module.
748
+ """
749
+ return (
750
+ importlib.import_module(self.app_module_import)
751
+ if self.app_module_import
752
+ else None
753
+ )
754
+
729
755
  @property
730
756
  def module(self) -> str:
731
757
  """Get the module name of the app.
@@ -733,6 +759,8 @@ class Config(Base):
733
759
  Returns:
734
760
  The module name.
735
761
  """
762
+ if self.app_module is not None:
763
+ return self.app_module.__name__
736
764
  return ".".join([self.app_name, self.app_name])
737
765
 
738
766
  def update_from_env(self) -> dict[str, Any]:
@@ -744,7 +772,7 @@ class Config(Base):
744
772
  """
745
773
  if self.env_file:
746
774
  try:
747
- from dotenv import load_dotenv # type: ignore
775
+ from dotenv import load_dotenv # pyright: ignore [reportMissingImports]
748
776
 
749
777
  # load env file if exists
750
778
  load_dotenv(self.env_file, override=True)
@@ -804,16 +832,16 @@ class Config(Base):
804
832
  if "api_url" not in self._non_default_attributes:
805
833
  # If running in Github Codespaces, override API_URL
806
834
  codespace_name = os.getenv("CODESPACE_NAME")
807
- GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN = os.getenv(
835
+ github_codespaces_port_forwarding_domain = os.getenv(
808
836
  "GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN"
809
837
  )
810
838
  # If running on Replit.com interactively, override API_URL to ensure we maintain the backend_port
811
839
  replit_dev_domain = os.getenv("REPLIT_DEV_DOMAIN")
812
840
  backend_port = kwargs.get("backend_port", self.backend_port)
813
- if codespace_name and GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN:
841
+ if codespace_name and github_codespaces_port_forwarding_domain:
814
842
  self.api_url = (
815
843
  f"https://{codespace_name}-{kwargs.get('backend_port', self.backend_port)}"
816
- f".{GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN}"
844
+ f".{github_codespaces_port_forwarding_domain}"
817
845
  )
818
846
  elif replit_dev_domain and backend_port:
819
847
  self.api_url = f"https://{replit_dev_domain}:{backend_port}"
@@ -871,7 +899,7 @@ def get_config(reload: bool = False) -> Config:
871
899
  return cached_rxconfig.config
872
900
 
873
901
  with _config_lock:
874
- sys_path = sys.path.copy()
902
+ orig_sys_path = sys.path.copy()
875
903
  sys.path.clear()
876
904
  sys.path.append(str(Path.cwd()))
877
905
  try:
@@ -879,9 +907,14 @@ def get_config(reload: bool = False) -> Config:
879
907
  return _get_config()
880
908
  except Exception:
881
909
  # If the module import fails, try to import with the original sys.path.
882
- sys.path.extend(sys_path)
910
+ sys.path.extend(orig_sys_path)
883
911
  return _get_config()
884
912
  finally:
913
+ # Find any entries added to sys.path by rxconfig.py itself.
914
+ extra_paths = [
915
+ p for p in sys.path if p not in orig_sys_path and p != str(Path.cwd())
916
+ ]
885
917
  # Restore the original sys.path.
886
918
  sys.path.clear()
887
- sys.path.extend(sys_path)
919
+ sys.path.extend(extra_paths)
920
+ sys.path.extend(orig_sys_path)
@@ -1,6 +1,7 @@
1
1
  """The constants package."""
2
2
 
3
3
  from .base import (
4
+ APP_HARNESS_FLAG,
4
5
  COOKIES,
5
6
  IS_LINUX,
6
7
  IS_MACOS,
reflex/constants/base.py CHANGED
@@ -52,7 +52,7 @@ class Dirs(SimpleNamespace):
52
52
  # The name of the postcss config file.
53
53
  POSTCSS_JS = "postcss.config.js"
54
54
  # The name of the states directory.
55
- STATES = "states"
55
+ STATES = ".states"
56
56
 
57
57
 
58
58
  class Reflex(SimpleNamespace):
@@ -75,6 +75,8 @@ class Reflex(SimpleNamespace):
75
75
  # If user sets REFLEX_DIR envroment variable use that instead.
76
76
  DIR = PlatformDirs(MODULE_NAME, False).user_data_path
77
77
 
78
+ LOGS_DIR = DIR / "logs"
79
+
78
80
  # The root directory of the reflex library.
79
81
  ROOT_DIR = Path(__file__).parents[2]
80
82
 
@@ -257,6 +259,7 @@ SESSION_STORAGE = "session_storage"
257
259
  # Testing variables.
258
260
  # Testing os env set by pytest when running a test case.
259
261
  PYTEST_CURRENT_TEST = "PYTEST_CURRENT_TEST"
262
+ APP_HARNESS_FLAG = "APP_HARNESS_FLAG"
260
263
 
261
264
  REFLEX_VAR_OPENING_TAG = "<reflex.Var>"
262
265
  REFLEX_VAR_CLOSING_TAG = "</reflex.Var>"
@@ -1,10 +1,10 @@
1
1
  """Compiler variables."""
2
2
 
3
+ import dataclasses
3
4
  import enum
4
5
  from enum import Enum
5
6
  from types import SimpleNamespace
6
7
 
7
- from reflex.base import Base
8
8
  from reflex.constants import Dirs
9
9
  from reflex.utils.imports import ImportVar
10
10
 
@@ -28,6 +28,8 @@ class Ext(SimpleNamespace):
28
28
  ZIP = ".zip"
29
29
  # The extension for executable files on Windows.
30
30
  EXE = ".exe"
31
+ # The extension for markdown files.
32
+ MD = ".md"
31
33
 
32
34
 
33
35
  class CompileVars(SimpleNamespace):
@@ -149,7 +151,8 @@ class MemoizationDisposition(enum.Enum):
149
151
  NEVER = "never"
150
152
 
151
153
 
152
- class MemoizationMode(Base):
154
+ @dataclasses.dataclass(frozen=True)
155
+ class MemoizationMode:
153
156
  """The mode for memoizing a Component."""
154
157
 
155
158
  # The conditions under which the component should be memoized.
@@ -39,7 +39,14 @@ class GitIgnore(SimpleNamespace):
39
39
  # The gitignore file.
40
40
  FILE = Path(".gitignore")
41
41
  # Files to gitignore.
42
- DEFAULTS = {Dirs.WEB, "*.db", "__pycache__/", "*.py[cod]", "assets/external/"}
42
+ DEFAULTS = {
43
+ Dirs.WEB,
44
+ Dirs.STATES,
45
+ "*.db",
46
+ "__pycache__/",
47
+ "*.py[cod]",
48
+ "assets/external/",
49
+ }
43
50
 
44
51
 
45
52
  class RequirementsTxt(SimpleNamespace):
@@ -37,10 +37,10 @@ class Bun(SimpleNamespace):
37
37
  """Bun constants."""
38
38
 
39
39
  # The Bun version.
40
- VERSION = "1.1.29"
40
+ VERSION = "1.2.0"
41
41
 
42
42
  # Min Bun Version
43
- MIN_VERSION = "0.7.0"
43
+ MIN_VERSION = "1.1.0"
44
44
 
45
45
  # URL to bun install script.
46
46
  INSTALL_URL = "https://raw.githubusercontent.com/reflex-dev/reflex/main/scripts/bun_install.sh"
@@ -178,21 +178,21 @@ class PackageJson(SimpleNamespace):
178
178
  PATH = "package.json"
179
179
 
180
180
  DEPENDENCIES = {
181
- "@babel/standalone": "7.26.0",
182
- "@emotion/react": "11.13.3",
183
- "axios": "1.7.7",
181
+ "@babel/standalone": "7.26.6",
182
+ "@emotion/react": "11.14.0",
183
+ "axios": "1.7.9",
184
184
  "json5": "2.2.3",
185
- "next": "14.2.16",
185
+ "next": "15.1.6",
186
186
  "next-sitemap": "4.2.3",
187
- "next-themes": "0.4.3",
187
+ "next-themes": "0.4.4",
188
188
  "react": "18.3.1",
189
189
  "react-dom": "18.3.1",
190
- "react-focus-lock": "2.13.2",
190
+ "react-focus-lock": "2.13.5",
191
191
  "socket.io-client": "4.8.1",
192
192
  "universal-cookie": "7.2.2",
193
193
  }
194
194
  DEV_DEPENDENCIES = {
195
195
  "autoprefixer": "10.4.20",
196
- "postcss": "8.4.49",
196
+ "postcss": "8.5.1",
197
197
  "postcss-import": "16.1.0",
198
198
  }
reflex/constants/style.py CHANGED
@@ -7,7 +7,7 @@ class Tailwind(SimpleNamespace):
7
7
  """Tailwind constants."""
8
8
 
9
9
  # The Tailwindcss version
10
- VERSION = "tailwindcss@3.4.15"
10
+ VERSION = "tailwindcss@3.4.17"
11
11
  # The Tailwind config.
12
12
  CONFIG = "tailwind.config.js"
13
13
  # Default Tailwind content paths
@@ -83,7 +83,7 @@ def _get_package_config(exit_on_fail: bool = True) -> dict:
83
83
  The package configuration.
84
84
 
85
85
  Raises:
86
- Exit: If the pyproject.toml file is not found.
86
+ Exit: If the pyproject.toml file is not found and exit_on_fail is True.
87
87
  """
88
88
  pyproject = Path(CustomComponents.PYPROJECT_TOML)
89
89
  try:
@@ -421,12 +421,13 @@ def _run_commands_in_subprocess(cmds: list[str]) -> bool:
421
421
  console.debug(f"Running command: {' '.join(cmds)}")
422
422
  try:
423
423
  result = subprocess.run(cmds, capture_output=True, text=True, check=True)
424
- console.debug(result.stdout)
425
- return True
426
424
  except subprocess.CalledProcessError as cpe:
427
425
  console.error(cpe.stdout)
428
426
  console.error(cpe.stderr)
429
427
  return False
428
+ else:
429
+ console.debug(result.stdout)
430
+ return True
430
431
 
431
432
 
432
433
  def _make_pyi_files():
@@ -771,7 +772,7 @@ def _validate_project_info():
771
772
  pyproject_toml = _get_package_config()
772
773
  project = pyproject_toml["project"]
773
774
  console.print(
774
- f'Double check the information before publishing: {project["name"]} version {project["version"]}'
775
+ f"Double check the information before publishing: {project['name']} version {project['version']}"
775
776
  )
776
777
 
777
778
  console.print("Update or enter to keep the current information.")
@@ -783,7 +784,7 @@ def _validate_project_info():
783
784
  author["name"] = console.ask("Author Name", default=author.get("name", ""))
784
785
  author["email"] = console.ask("Author Email", default=author.get("email", ""))
785
786
 
786
- console.print(f'Current keywords are: {project.get("keywords") or []}')
787
+ console.print(f"Current keywords are: {project.get('keywords') or []}")
787
788
  keyword_action = console.ask(
788
789
  "Keep, replace or append?", choices=["k", "r", "a"], default="k"
789
790
  )
@@ -924,17 +925,18 @@ def _get_file_from_prompt_in_loop() -> Tuple[bytes, str] | None:
924
925
  image_file = file_extension = None
925
926
  while image_file is None:
926
927
  image_filepath = Path(
927
- console.ask("Upload a preview image of your demo app (enter to skip)")
928
+ console.ask("Upload a preview image of your demo app (enter to skip)") # pyright: ignore [reportArgumentType]
928
929
  )
929
930
  if not image_filepath:
930
931
  break
931
932
  file_extension = image_filepath.suffix
932
933
  try:
933
934
  image_file = image_filepath.read_bytes()
934
- return image_file, file_extension
935
935
  except OSError as ose:
936
936
  console.error(f"Unable to read the {file_extension} file due to {ose}")
937
937
  raise typer.Exit(code=1) from ose
938
+ else:
939
+ return image_file, file_extension
938
940
 
939
941
  console.debug(f"File extension detected: {file_extension}")
940
942
  return None