reflex 0.8.14.post1__py3-none-any.whl → 0.8.15a0__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.

@@ -17,7 +17,7 @@ class Constants(SimpleNamespace):
17
17
  """Tailwind constants."""
18
18
 
19
19
  # The Tailwindcss version
20
- VERSION = "tailwindcss@4.1.13"
20
+ VERSION = "tailwindcss@4.1.14"
21
21
  # The Tailwind config.
22
22
  CONFIG = "tailwind.config.js"
23
23
  # Default Tailwind content paths
@@ -156,7 +156,7 @@ class TailwindV4Plugin(TailwindPlugin):
156
156
  return [
157
157
  *super().get_frontend_development_dependencies(**context),
158
158
  Constants.VERSION,
159
- "@tailwindcss/postcss@4.1.13",
159
+ "@tailwindcss/postcss@4.1.14",
160
160
  ]
161
161
 
162
162
  def pre_compile(self, **context):
reflex/reflex.py CHANGED
@@ -11,12 +11,14 @@ from reflex_cli.v2.deployments import hosting_cli
11
11
 
12
12
  from reflex import constants
13
13
  from reflex.config import get_config
14
- from reflex.constants.base import LITERAL_ENV
15
14
  from reflex.custom_components.custom_components import custom_components_cli
16
15
  from reflex.environment import environment
17
- from reflex.state import reset_disk_state_manager
18
- from reflex.utils import console, redir, telemetry
19
- from reflex.utils.exec import should_use_granian
16
+ from reflex.utils import console
17
+
18
+ if TYPE_CHECKING:
19
+ from reflex_cli.constants.base import LogLevel as HostingLogLevel
20
+
21
+ from reflex.constants.base import LITERAL_ENV
20
22
 
21
23
 
22
24
  def set_loglevel(ctx: click.Context, self: click.Parameter, value: str | None):
@@ -40,6 +42,8 @@ def cli():
40
42
 
41
43
  loglevel_option = click.option(
42
44
  "--loglevel",
45
+ "--log-level",
46
+ "loglevel",
43
47
  type=click.Choice(
44
48
  [loglevel.value for loglevel in constants.LogLevel],
45
49
  case_sensitive=False,
@@ -63,7 +67,9 @@ def _init(
63
67
  exec.output_system_info()
64
68
 
65
69
  if ai:
66
- redir.reflex_build_redirect()
70
+ from reflex.utils.redir import reflex_build_redirect
71
+
72
+ reflex_build_redirect()
67
73
  return
68
74
 
69
75
  # Validate the app name.
@@ -136,7 +142,9 @@ def _run(
136
142
  """Run the app in the given directory."""
137
143
  import atexit
138
144
 
139
- from reflex.utils import build, exec, prerequisites, processes
145
+ from reflex.state import reset_disk_state_manager
146
+ from reflex.utils import build, exec, prerequisites, processes, telemetry
147
+ from reflex.utils.exec import should_use_granian
140
148
 
141
149
  config = get_config()
142
150
 
@@ -535,6 +543,8 @@ def login():
535
543
  validated_info = hosting_cli.login()
536
544
  if validated_info is not None:
537
545
  _skip_compile() # Allow running outside of an app dir
546
+ from reflex.utils import telemetry
547
+
538
548
  telemetry.send("login", user_uuid=validated_info.get("user_id"))
539
549
 
540
550
 
@@ -838,10 +848,6 @@ def rename(new_name: str):
838
848
  rename_app(new_name, get_config().loglevel)
839
849
 
840
850
 
841
- if TYPE_CHECKING:
842
- from reflex_cli.constants.base import LogLevel as HostingLogLevel
843
-
844
-
845
851
  def _convert_reflex_loglevel_to_reflex_cli_loglevel(
846
852
  loglevel: constants.LogLevel,
847
853
  ) -> HostingLogLevel:
reflex/state.py CHANGED
@@ -17,19 +17,15 @@ import typing
17
17
  import warnings
18
18
  from collections.abc import AsyncIterator, Callable, Sequence
19
19
  from hashlib import md5
20
+ from importlib.util import find_spec
20
21
  from types import FunctionType
21
22
  from typing import TYPE_CHECKING, Any, BinaryIO, ClassVar, TypeVar, cast, get_type_hints
22
23
 
23
- import pydantic.v1 as pydantic
24
- from pydantic import BaseModel as BaseModelV2
25
- from pydantic.v1 import BaseModel as BaseModelV1
26
- from pydantic.v1.fields import ModelField
27
24
  from rich.markup import escape
28
25
  from typing_extensions import Self
29
26
 
30
27
  import reflex.istate.dynamic
31
28
  from reflex import constants, event
32
- from reflex.base import Base
33
29
  from reflex.constants.state import FIELD_MARKER
34
30
  from reflex.environment import PerformanceMode, environment
35
31
  from reflex.event import (
@@ -94,13 +90,11 @@ if environment.REFLEX_PERF_MODE.get() != PerformanceMode.OFF:
94
90
  VAR_TYPE = TypeVar("VAR_TYPE")
95
91
 
96
92
 
97
- def _no_chain_background_task(
98
- state_cls: type[BaseState], name: str, fn: Callable
99
- ) -> Callable:
93
+ def _no_chain_background_task(state: BaseState, name: str, fn: Callable) -> Callable:
100
94
  """Protect against directly chaining a background task from another event handler.
101
95
 
102
96
  Args:
103
- state_cls: The state class that the event handler is in.
97
+ state: The state instance the background task is bound to.
104
98
  name: The name of the background task.
105
99
  fn: The background task coroutine function / generator.
106
100
 
@@ -110,7 +104,7 @@ def _no_chain_background_task(
110
104
  Raises:
111
105
  TypeError: If the background task is not async.
112
106
  """
113
- call = f"{state_cls.__name__}.{name}"
107
+ call = f"{type(state).__name__}.{name}"
114
108
  message = (
115
109
  f"Cannot directly call background task {name!r}, use "
116
110
  f"`yield {call}` or `return {call}` instead."
@@ -259,10 +253,6 @@ class EventHandlerSetVar(EventHandler):
259
253
  return super().__call__(*args)
260
254
 
261
255
 
262
- if TYPE_CHECKING:
263
- from pydantic.v1.fields import ModelField
264
-
265
-
266
256
  def get_var_for_field(cls: type[BaseState], name: str, f: Field) -> Var:
267
257
  """Get a Var instance for a state field.
268
258
 
@@ -479,7 +469,7 @@ class BaseState(EvenMoreBasicBaseState):
479
469
 
480
470
  Args:
481
471
  mixin: Whether the subclass is a mixin and should not be initialized.
482
- **kwargs: The kwargs to pass to the pydantic init_subclass method.
472
+ **kwargs: The kwargs to pass to the init_subclass method.
483
473
 
484
474
  Raises:
485
475
  StateValueError: If a substate class shadows another.
@@ -739,7 +729,7 @@ class BaseState(EvenMoreBasicBaseState):
739
729
  mixin
740
730
  for mixin in cls.__mro__
741
731
  if (
742
- mixin not in [pydantic.BaseModel, Base, cls]
732
+ mixin is not cls
743
733
  and issubclass(mixin, BaseState)
744
734
  and mixin._mixin is True
745
735
  )
@@ -1090,7 +1080,7 @@ class BaseState(EvenMoreBasicBaseState):
1090
1080
  _var_data=VarData.from_state(cls, name),
1091
1081
  ).guess_type()
1092
1082
 
1093
- # add the pydantic field dynamically (must be done before _init_var)
1083
+ # add the field dynamically (must be done before _init_var)
1094
1084
  cls.add_field(name, var, default_value)
1095
1085
 
1096
1086
  cls._init_var(name, var)
@@ -1188,7 +1178,7 @@ class BaseState(EvenMoreBasicBaseState):
1188
1178
  name: The name of the var.
1189
1179
  prop: The var to set the default value for.
1190
1180
  """
1191
- # Get the pydantic field for the var.
1181
+ # Get the field for the var.
1192
1182
  field = cls.get_fields()[name]
1193
1183
 
1194
1184
  if field.default is None and not types.is_optional(prop._var_type):
@@ -1349,7 +1339,7 @@ class BaseState(EvenMoreBasicBaseState):
1349
1339
  if name in event_handlers:
1350
1340
  handler = event_handlers[name]
1351
1341
  if handler.is_background:
1352
- fn = _no_chain_background_task(type(self), name, handler.fn)
1342
+ fn = _no_chain_background_task(self, name, handler.fn)
1353
1343
  else:
1354
1344
  fn = functools.partial(handler.fn, self)
1355
1345
  fn.__module__ = handler.fn.__module__
@@ -1465,7 +1455,7 @@ class BaseState(EvenMoreBasicBaseState):
1465
1455
 
1466
1456
  @classmethod
1467
1457
  @functools.lru_cache
1468
- def _is_client_storage(cls, prop_name_or_field: str | ModelField) -> bool:
1458
+ def _is_client_storage(cls, prop_name_or_field: str | Field) -> bool:
1469
1459
  """Check if the var is a client storage var.
1470
1460
 
1471
1461
  Args:
@@ -1872,10 +1862,16 @@ class BaseState(EvenMoreBasicBaseState):
1872
1862
  if key in hinted_args.__fields__
1873
1863
  }
1874
1864
  )
1875
- elif dataclasses.is_dataclass(hinted_args) or issubclass(
1876
- hinted_args, (Base, BaseModelV1, BaseModelV2)
1877
- ):
1865
+ elif dataclasses.is_dataclass(hinted_args):
1878
1866
  payload[arg] = hinted_args(**value)
1867
+ elif find_spec("pydantic"):
1868
+ from pydantic import BaseModel as BaseModelV2
1869
+ from pydantic.v1 import BaseModel as BaseModelV1
1870
+
1871
+ if issubclass(hinted_args, BaseModelV1):
1872
+ payload[arg] = hinted_args.parse_obj(value)
1873
+ elif issubclass(hinted_args, BaseModelV2):
1874
+ payload[arg] = hinted_args.model_validate(value)
1879
1875
  elif isinstance(value, list) and (hinted_args is set or hinted_args is set):
1880
1876
  payload[arg] = set(value)
1881
1877
  elif isinstance(value, list) and (
@@ -2142,7 +2138,7 @@ class BaseState(EvenMoreBasicBaseState):
2142
2138
  Args:
2143
2139
  include_computed: Whether to include computed vars.
2144
2140
  initial: Whether to get the initial value of computed vars.
2145
- **kwargs: Kwargs to pass to the pydantic dict method.
2141
+ **kwargs: Kwargs to pass to the dict method.
2146
2142
 
2147
2143
  Returns:
2148
2144
  The object as a dictionary.
@@ -2626,7 +2622,7 @@ class ComponentState(State, mixin=True):
2626
2622
 
2627
2623
  Args:
2628
2624
  mixin: Whether the subclass is a mixin and should not be initialized.
2629
- **kwargs: The kwargs to pass to the pydantic init_subclass method.
2625
+ **kwargs: The kwargs to pass to the init_subclass method.
2630
2626
  """
2631
2627
  super().__init_subclass__(mixin=mixin, **kwargs)
2632
2628
 
reflex/testing.py CHANGED
@@ -21,6 +21,7 @@ import time
21
21
  import types
22
22
  from collections.abc import AsyncIterator, Callable, Coroutine, Sequence
23
23
  from http.server import SimpleHTTPRequestHandler
24
+ from importlib.util import find_spec
24
25
  from pathlib import Path
25
26
  from typing import TYPE_CHECKING, Any, Literal, TypeVar
26
27
 
@@ -320,12 +321,13 @@ class AppHarness:
320
321
  await self.app_instance.sio.shutdown()
321
322
 
322
323
  # sqlalchemy async engine shutdown handler
323
- try:
324
- async_engine = reflex.model.get_async_engine(None)
325
- except ValueError:
326
- pass
327
- else:
328
- await async_engine.dispose()
324
+ if find_spec("sqlmodel"):
325
+ try:
326
+ async_engine = reflex.model.get_async_engine(None)
327
+ except ValueError:
328
+ pass
329
+ else:
330
+ await async_engine.dispose()
329
331
 
330
332
  await original_shutdown(*args, **kwargs)
331
333
 
reflex/utils/build.py CHANGED
@@ -187,7 +187,11 @@ def _duplicate_index_html_to_parent_directory(directory: Path):
187
187
 
188
188
 
189
189
  def build():
190
- """Build the app for deployment."""
190
+ """Build the app for deployment.
191
+
192
+ Raises:
193
+ SystemExit: If the build process fails.
194
+ """
191
195
  wdir = prerequisites.get_web_dir()
192
196
 
193
197
  # Clean the static directory if it exists.
@@ -214,6 +218,12 @@ def build():
214
218
  },
215
219
  )
216
220
  processes.show_progress("Creating Production Build", process, checkpoints)
221
+ process.wait()
222
+ if process.returncode != 0:
223
+ console.error(
224
+ "Failed to build the frontend. Please run with --loglevel debug for more information.",
225
+ )
226
+ raise SystemExit(1)
217
227
  _duplicate_index_html_to_parent_directory(wdir / constants.Dirs.STATIC)
218
228
 
219
229
  spa_fallback = wdir / constants.Dirs.STATIC / constants.ReactRouter.SPA_FALLBACK
reflex/utils/compat.py CHANGED
@@ -1,8 +1,9 @@
1
1
  """Compatibility hacks and helpers."""
2
2
 
3
- import contextlib
4
- import sys
5
- from typing import Any
3
+ from typing import TYPE_CHECKING
4
+
5
+ if TYPE_CHECKING:
6
+ from pydantic.fields import FieldInfo
6
7
 
7
8
 
8
9
  async def windows_hot_reload_lifespan_hack():
@@ -29,63 +30,17 @@ async def windows_hot_reload_lifespan_hack():
29
30
  pass
30
31
 
31
32
 
32
- @contextlib.contextmanager
33
- def pydantic_v1_patch():
34
- """A context manager that patches the Pydantic module to mimic v1 behaviour.
35
-
36
- Yields:
37
- None when the Pydantic module is patched.
38
- """
39
- import pydantic
40
-
41
- if pydantic.__version__.startswith("1."):
42
- # pydantic v1 is already installed
43
- yield
44
- return
45
-
46
- patched_modules = [
47
- "pydantic",
48
- "pydantic.fields",
49
- "pydantic.errors",
50
- "pydantic.main",
51
- ]
52
- originals = {module: sys.modules.get(module) for module in patched_modules}
53
- try:
54
- import pydantic.v1
55
-
56
- sys.modules["pydantic.fields"] = pydantic.v1.fields # pyright: ignore [reportAttributeAccessIssue]
57
- sys.modules["pydantic.main"] = pydantic.v1.main # pyright: ignore [reportAttributeAccessIssue]
58
- sys.modules["pydantic.errors"] = pydantic.v1.errors # pyright: ignore [reportAttributeAccessIssue]
59
- sys.modules["pydantic"] = pydantic.v1
60
- yield
61
- except (ImportError, AttributeError):
62
- # pydantic v1 is already installed
63
- yield
64
- finally:
65
- # Restore the original Pydantic module
66
- for k, original in originals.items():
67
- if k in sys.modules:
68
- if original:
69
- sys.modules[k] = original
70
- else:
71
- del sys.modules[k]
72
-
73
-
74
- with pydantic_v1_patch():
75
- import sqlmodel as sqlmodel
76
-
77
-
78
- def sqlmodel_field_has_primary_key(field: Any) -> bool:
79
- """Determines if a field is a priamary.
33
+ def sqlmodel_field_has_primary_key(field_info: "FieldInfo") -> bool:
34
+ """Determines if a field is a primary.
80
35
 
81
36
  Args:
82
- field: a rx.model field
37
+ field_info: a rx.model field
83
38
 
84
39
  Returns:
85
- If field is a primary key (Bool)
40
+ If field_info is a primary key (Bool)
86
41
  """
87
- if getattr(field.field_info, "primary_key", None) is True:
42
+ if getattr(field_info, "primary_key", None) is True:
88
43
  return True
89
- if getattr(field.field_info, "sa_column", None) is None:
44
+ if getattr(field_info, "sa_column", None) is None:
90
45
  return False
91
- return bool(getattr(field.field_info.sa_column, "primary_key", None))
46
+ return bool(getattr(field_info.sa_column, "primary_key", None)) # pyright: ignore[reportAttributeAccessIssue]
@@ -15,7 +15,6 @@ from pathlib import Path
15
15
  from types import ModuleType
16
16
  from typing import NamedTuple
17
17
 
18
- from alembic.util.exc import CommandError
19
18
  from packaging import version
20
19
  from redis import Redis as RedisSync
21
20
  from redis.asyncio import Redis
@@ -639,6 +638,8 @@ def check_schema_up_to_date():
639
638
  if get_config().db_url is None or not environment.ALEMBIC_CONFIG.get().exists():
640
639
  return
641
640
  with model.Model.get_db_engine().connect() as connection:
641
+ from alembic.util.exc import CommandError
642
+
642
643
  try:
643
644
  if model.Model.alembic_autogenerate(
644
645
  connection=connection,
@@ -12,13 +12,11 @@ import warnings
12
12
  from collections.abc import Callable, Mapping, Sequence
13
13
  from datetime import date, datetime, time, timedelta
14
14
  from enum import Enum
15
+ from importlib.util import find_spec
15
16
  from pathlib import Path
16
17
  from typing import Any, Literal, TypeVar, get_type_hints, overload
17
18
  from uuid import UUID
18
19
 
19
- from pydantic import BaseModel as BaseModelV2
20
- from pydantic.v1 import BaseModel as BaseModelV1
21
-
22
20
  from reflex.base import Base
23
21
  from reflex.constants.colors import Color
24
22
  from reflex.utils import console, types
@@ -281,24 +279,13 @@ def serialize_base(value: Base) -> dict:
281
279
  }
282
280
 
283
281
 
284
- @serializer(to=dict)
285
- def serialize_base_model_v1(model: BaseModelV1) -> dict:
286
- """Serialize a pydantic v1 BaseModel instance.
287
-
288
- Args:
289
- model: The BaseModel to serialize.
290
-
291
- Returns:
292
- The serialized BaseModel.
293
- """
294
- return model.dict()
295
-
296
-
297
- if BaseModelV1 is not BaseModelV2:
282
+ if find_spec("pydantic"):
283
+ from pydantic import BaseModel as BaseModelV2
284
+ from pydantic.v1 import BaseModel as BaseModelV1
298
285
 
299
286
  @serializer(to=dict)
300
- def serialize_base_model_v2(model: BaseModelV2) -> dict:
301
- """Serialize a pydantic v2 BaseModel instance.
287
+ def serialize_base_model_v1(model: BaseModelV1) -> dict:
288
+ """Serialize a pydantic v1 BaseModel instance.
302
289
 
303
290
  Args:
304
291
  model: The BaseModel to serialize.
@@ -306,7 +293,21 @@ if BaseModelV1 is not BaseModelV2:
306
293
  Returns:
307
294
  The serialized BaseModel.
308
295
  """
309
- return model.model_dump()
296
+ return model.dict()
297
+
298
+ if BaseModelV1 is not BaseModelV2:
299
+
300
+ @serializer(to=dict)
301
+ def serialize_base_model_v2(model: BaseModelV2) -> dict:
302
+ """Serialize a pydantic v2 BaseModel instance.
303
+
304
+ Args:
305
+ model: The BaseModel to serialize.
306
+
307
+ Returns:
308
+ The serialized BaseModel.
309
+ """
310
+ return model.model_dump()
310
311
 
311
312
 
312
313
  @serializer
reflex/utils/telemetry.py CHANGED
@@ -1,7 +1,5 @@
1
1
  """Anonymous telemetry for Reflex."""
2
2
 
3
- from __future__ import annotations
4
-
5
3
  import asyncio
6
4
  import dataclasses
7
5
  import importlib.metadata