reflex 0.7.1a4__py3-none-any.whl → 0.7.1a5__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.

@@ -0,0 +1,110 @@
1
+ export default function pythonFormat(number, formatSpecifier) {
2
+ // Parse the format specifier
3
+ const formatRegex = /^(?<fill>.)?(?<align>[<>=^])?(?<sign>[-+ ])?(?<alt>#)?(?<zero>0)?(?<width>\d+)?(?<grouping>[_,])?(?<precision>\.\d+)?(?<type>[a-zA-Z])?$/;
4
+ const match = formatSpecifier.match(formatRegex);
5
+
6
+ if (!match) {
7
+ throw new Error("Invalid format specifier.");
8
+ }
9
+
10
+ const {
11
+ fill = " ",
12
+ align = ">",
13
+ sign = "-",
14
+ alt,
15
+ zero,
16
+ width,
17
+ grouping,
18
+ precision,
19
+ type = "g",
20
+ } = match.groups;
21
+
22
+ // Handle precision for floats
23
+ let formattedNumber;
24
+ if (type === "f" || type === "e" || type === "g" || type === "%") {
25
+ const precisionValue = precision ? parseInt(precision.slice(1), 10) : 6;
26
+ switch (type) {
27
+ case "f":
28
+ formattedNumber = number.toFixed(precisionValue);
29
+ break;
30
+ case "e":
31
+ formattedNumber = number.toExponential(precisionValue);
32
+ break;
33
+ case "g":
34
+ formattedNumber = number.toPrecision(precisionValue);
35
+ break;
36
+ case "%":
37
+ formattedNumber = (number * 100).toFixed(precisionValue) + "%";
38
+ break;
39
+ }
40
+ } else if (type === "d" || type === "b" || type === "o" || type === "x" || type === "X") {
41
+ // Handle integer types
42
+ const base = {
43
+ b: 2,
44
+ o: 8,
45
+ d: 10,
46
+ x: 16,
47
+ X: 16,
48
+ }[type];
49
+ formattedNumber = Math.floor(number).toString(base);
50
+ if (type === "X") {
51
+ formattedNumber = formattedNumber.toUpperCase();
52
+ }
53
+ if (alt && (type === "o" || type === "x" || type === "X")) {
54
+ formattedNumber = (type === "o" ? "0o" : "0x") + formattedNumber;
55
+ }
56
+ } else {
57
+ throw new Error(`Unsupported format type: ${type}`);
58
+ }
59
+
60
+ // Handle sign
61
+ if (sign !== "-") {
62
+ if (number >= 0) {
63
+ formattedNumber = sign === "+" ? "+" + formattedNumber : sign === " " ? " " + formattedNumber : formattedNumber;
64
+ } else {
65
+ formattedNumber = "-" + formattedNumber;
66
+ }
67
+ }
68
+
69
+ // Handle grouping (thousands separator)
70
+ if (grouping) {
71
+ const parts = formattedNumber.split(".");
72
+ parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, grouping === "," ? "," : "_");
73
+ formattedNumber = parts.join(".");
74
+ }
75
+
76
+ // Handle zero-padding and width
77
+ if (width) {
78
+ const padLength = Math.max(0, parseInt(width, 10) - formattedNumber.length);
79
+ if (padLength > 0) {
80
+ const padChar = zero ? "0" : fill;
81
+ if (align === ">") {
82
+ formattedNumber = formattedNumber.padStart(padLength + formattedNumber.length, padChar);
83
+ } else if (align === "<") {
84
+ formattedNumber = formattedNumber.padEnd(padLength + formattedNumber.length, padChar);
85
+ } else if (align === "^") {
86
+ const leftPad = Math.floor(padLength / 2);
87
+ const rightPad = Math.ceil(padLength / 2);
88
+ formattedNumber = formattedNumber
89
+ .padStart(leftPad + formattedNumber.length, padChar)
90
+ .padEnd(rightPad + formattedNumber.length, padChar);
91
+ } else if (align === "=") {
92
+ // Handle numeric alignment (sign-aware padding)
93
+ const signChar = formattedNumber.match(/^[+-]/)?.[0] || "";
94
+ const numPart = formattedNumber.slice(signChar.length);
95
+ formattedNumber = signChar + numPart.padStart(padLength + numPart.length, padChar);
96
+ }
97
+ }
98
+ }
99
+
100
+ return formattedNumber;
101
+ }
102
+
103
+ // Example usage:
104
+ console.log(pythonFormat(1234.5678, "10.2f")); // " 1234.57"
105
+ console.log(pythonFormat(-1234.5678, "+.3f")); // "-1234.568"
106
+ console.log(pythonFormat(1234.5678, "0>+10,.2f")); // "0+1,234.57"
107
+ console.log(pythonFormat(255, "#04x")); // "0xff"
108
+ console.log(pythonFormat(255, "08b")); // "11111111"
109
+ console.log(pythonFormat(1234567, "_,d")); // "1_234_567"
110
+ console.log(pythonFormat(0.12345, ".2%")); // "12.35%"
reflex/app.py CHANGED
@@ -986,12 +986,15 @@ class App(MiddlewareMixin, LifespanMixin):
986
986
 
987
987
  def _setup_sticky_badge(self):
988
988
  """Add the sticky badge to the app."""
989
- for k, component in self._pages.items():
990
- # Would be nice to share single sticky_badge across all pages, but
991
- # it bungles the StatefulComponent compile step.
989
+ from reflex.components.component import memo
990
+
991
+ @memo
992
+ def memoized_badge():
992
993
  sticky_badge = sticky()
993
994
  sticky_badge._add_style_recursive({})
994
- self._pages[k] = Fragment.create(sticky_badge, component)
995
+ return sticky_badge
996
+
997
+ self.app_wraps[(0, "StickyBadge")] = lambda _: memoized_badge()
995
998
 
996
999
  def _apply_decorated_pages(self):
997
1000
  """Add @rx.page decorated pages to the app.
@@ -5,7 +5,7 @@ from __future__ import annotations
5
5
  from typing import Any, Dict, Optional, overload
6
6
 
7
7
  from reflex.components.base.fragment import Fragment
8
- from reflex.components.component import BaseComponent, Component, MemoizationLeaf
8
+ from reflex.components.component import BaseComponent, Component
9
9
  from reflex.components.tags import CondTag, Tag
10
10
  from reflex.constants import Dirs
11
11
  from reflex.style import LIGHT_COLOR_MODE, resolved_color_mode
@@ -19,7 +19,7 @@ _IS_TRUE_IMPORT: ImportDict = {
19
19
  }
20
20
 
21
21
 
22
- class Cond(MemoizationLeaf):
22
+ class Cond(Component):
23
23
  """Render one of two components based on a condition."""
24
24
 
25
25
  # The cond to determine which component to render.
@@ -0,0 +1,3 @@
1
+ {
2
+ "elements/forms.pyi": "e05f3ed762ea47f37f32550f8b9105e5"
3
+ }
reflex/state.py CHANGED
@@ -1397,6 +1397,29 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
1397
1397
  for substate in self.substates.values():
1398
1398
  substate.reset()
1399
1399
 
1400
+ @classmethod
1401
+ @functools.lru_cache
1402
+ def _is_client_storage(cls, prop_name_or_field: str | ModelField) -> bool:
1403
+ """Check if the var is a client storage var.
1404
+
1405
+ Args:
1406
+ prop_name_or_field: The name of the var or the field itself.
1407
+
1408
+ Returns:
1409
+ Whether the var is a client storage var.
1410
+ """
1411
+ if isinstance(prop_name_or_field, str):
1412
+ field = cls.get_fields().get(prop_name_or_field)
1413
+ else:
1414
+ field = prop_name_or_field
1415
+ return field is not None and (
1416
+ isinstance(field.default, ClientStorageBase)
1417
+ or (
1418
+ isinstance(field.type_, type)
1419
+ and issubclass(field.type_, ClientStorageBase)
1420
+ )
1421
+ )
1422
+
1400
1423
  def _reset_client_storage(self):
1401
1424
  """Reset client storage base vars to their default values."""
1402
1425
  # Client-side storage is reset during hydrate so that clearing cookies
@@ -1404,10 +1427,7 @@ class BaseState(Base, ABC, extra=pydantic.Extra.allow):
1404
1427
  fields = self.get_fields()
1405
1428
  for prop_name in self.base_vars:
1406
1429
  field = fields[prop_name]
1407
- if isinstance(field.default, ClientStorageBase) or (
1408
- isinstance(field.type_, type)
1409
- and issubclass(field.type_, ClientStorageBase)
1410
- ):
1430
+ if self._is_client_storage(field):
1411
1431
  setattr(self, prop_name, copy.deepcopy(field.default))
1412
1432
 
1413
1433
  # Recursively reset the substate client storage.
@@ -2331,8 +2351,9 @@ class UpdateVarsInternalState(State):
2331
2351
  for var, value in vars.items():
2332
2352
  state_name, _, var_name = var.rpartition(".")
2333
2353
  var_state_cls = State.get_class_substate(state_name)
2334
- var_state = await self.get_state(var_state_cls)
2335
- setattr(var_state, var_name, value)
2354
+ if var_state_cls._is_client_storage(var_name):
2355
+ var_state = await self.get_state(var_state_cls)
2356
+ setattr(var_state, var_name, value)
2336
2357
 
2337
2358
 
2338
2359
  class OnLoadInternalState(State):
@@ -23,7 +23,7 @@ import zipfile
23
23
  from datetime import datetime
24
24
  from pathlib import Path
25
25
  from types import ModuleType
26
- from typing import Any, Callable, List, NamedTuple, Optional
26
+ from typing import Callable, List, NamedTuple, Optional
27
27
  from urllib.parse import urlparse
28
28
 
29
29
  import httpx
@@ -2025,38 +2025,3 @@ def get_user_tier():
2025
2025
  if authenticated_token[0]
2026
2026
  else "anonymous"
2027
2027
  )
2028
-
2029
-
2030
- def check_config_option_in_tier(
2031
- option_name: str,
2032
- allowed_tiers: list[str],
2033
- fallback_value: Any,
2034
- help_link: str | None = None,
2035
- ):
2036
- """Check if a config option is allowed for the authenticated user's current tier.
2037
-
2038
- Args:
2039
- option_name: The name of the option to check.
2040
- allowed_tiers: The tiers that are allowed to use the option.
2041
- fallback_value: The fallback value if the option is not allowed.
2042
- help_link: The help link to show to a user that is authenticated.
2043
- """
2044
- config = get_config()
2045
- current_tier = get_user_tier()
2046
-
2047
- if current_tier == "anonymous":
2048
- the_remedy = (
2049
- "You are currently logged out. Run `reflex login` to access this option."
2050
- )
2051
- else:
2052
- the_remedy = (
2053
- f"Your current subscription tier is `{current_tier}`. "
2054
- f"Please upgrade to {allowed_tiers} to access this option. "
2055
- )
2056
- if help_link:
2057
- the_remedy += f"See {help_link} for more information."
2058
-
2059
- if current_tier not in allowed_tiers:
2060
- console.warn(f"Config option `{option_name}` is restricted. {the_remedy}")
2061
- setattr(config, option_name, fallback_value)
2062
- config._set_persistent(**{option_name: fallback_value})
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: reflex
3
- Version: 0.7.1a4
3
+ Version: 0.7.1a5
4
4
  Summary: Web apps in pure Python.
5
5
  License: Apache-2.0
6
6
  Keywords: web,framework
@@ -32,6 +32,7 @@ reflex/.templates/web/styles/tailwind.css,sha256=wGOoICTy1G0e5bWZ4LYOVgRa3ZT7M44
32
32
  reflex/.templates/web/utils/client_side_routing.js,sha256=za3bslTR0cKLC4h-bxAr48nJFj0nPwrj28Dlv2A3dV4,1431
33
33
  reflex/.templates/web/utils/helpers/dataeditor.js,sha256=anZgi8RJ_J0yqDez1Ks51fNDIQOvP3WkIm1QRDwccSk,1622
34
34
  reflex/.templates/web/utils/helpers/debounce.js,sha256=xGhtTRtS_xIcaeqnYVvYJNseLgQVk-DW-eFiHJYO9As,528
35
+ reflex/.templates/web/utils/helpers/format.js,sha256=vubW6xMJkibEjkzmPUfG7jfrrmJe23hDG0aBnsR-a_8,4193
35
36
  reflex/.templates/web/utils/helpers/paste.js,sha256=ef30HsR83jRzzvZnl8yV79yqFP8TC_u8SlN99cCS_OM,1799
36
37
  reflex/.templates/web/utils/helpers/range.js,sha256=FevdZzCVxjF57ullfjpcUpeOXRxh5v09YnBB0jPbrS4,1152
37
38
  reflex/.templates/web/utils/helpers/throttle.js,sha256=qxeyaEojaTeX36FPGftzVWrzDsRQU4iqg3U9RJz9Vj4,566
@@ -40,7 +41,7 @@ reflex/__init__.py,sha256=64HB9b6MKesl3Yv6aZMsozdMKKpgnxirKk-aeN45UYY,10341
40
41
  reflex/__init__.pyi,sha256=j4ZkO-mKKw5dFBhJVbaOg7AlncO-JCckV2cHENPiLG0,11303
41
42
  reflex/__main__.py,sha256=6cVrGEyT3j3tEvlEVUatpaYfbB5EF3UVY-6vc_Z7-hw,108
42
43
  reflex/admin.py,sha256=_3pkkauMiTGJJ0kwAEBnsUWAgZZ_1WNnCaaObbhpmUI,374
43
- reflex/app.py,sha256=ksQaxm8GIDQjxFTQc5rtGF9gQC0CxS0itjCnHzBMS04,68950
44
+ reflex/app.py,sha256=TdRgsg9M4NvuBla4C5XpIsSUlYyNil-RcwZCs_n96-s,68894
44
45
  reflex/app_mixins/__init__.py,sha256=Oegz3-gZLP9p2OAN5ALNbsgxuNQfS6lGZgQA8cc-9mQ,137
45
46
  reflex/app_mixins/lifespan.py,sha256=Xs5KiidoyO921oaBuEg7zaR8B1_SPYDZLouel6u9PRo,3298
46
47
  reflex/app_mixins/middleware.py,sha256=lB8I67SEbqcJhp3aqMLZFIZekCYKeMby-Ph2sedIYJI,3349
@@ -90,7 +91,7 @@ reflex/components/core/client_side_routing.pyi,sha256=iSugaj073JtHey6oUOj5dGgDHB
90
91
  reflex/components/core/clipboard.py,sha256=knmLnwLx5c3iqejsCUw3z8pIBOTgBunr6LjJxxa8MNA,3372
91
92
  reflex/components/core/clipboard.pyi,sha256=wsUnimvf8skgSVyuUgYncERPA8untZ3swYWfraKlh-Q,3130
92
93
  reflex/components/core/colors.py,sha256=-hzVGLEq3TiqroqzMi_YzGBCPXMvkNsen3pS_NzIQNk,590
93
- reflex/components/core/cond.py,sha256=a3ICVQoIT-_Md1LTpXcMhykdCGdaC-R28YkSLuUkDE0,5728
94
+ reflex/components/core/cond.py,sha256=xUQucotwDxbvDzBrTxqWMutvKUU3-qeR5oEpTW-nTAc,5705
94
95
  reflex/components/core/debounce.py,sha256=pRrjHcKz9U0V1bIypuC6V67KzOl0VZr91k8udUGtJlc,4926
95
96
  reflex/components/core/debounce.pyi,sha256=5u-sW2EBxws8EPfLCYpNb0r8k5fh6hqpOTt1TXgZc4I,2986
96
97
  reflex/components/core/foreach.py,sha256=ZasnJB4rEx8FCuV3soFRuCrM2Ll2OHBdqNPyz_UL5kQ,5722
@@ -143,6 +144,7 @@ reflex/components/el/elements/tables.py,sha256=Rt-C07s39TQm_dHSMaly2J7yD0OZhx9q6
143
144
  reflex/components/el/elements/tables.pyi,sha256=mVLEfupDUDYv0eECXZMzoF2WoBV6BP6FCnm_y2F-QYk,102131
144
145
  reflex/components/el/elements/typography.py,sha256=WJZ-FFeHG22loZKGR3MH4YrkqjyzX4Mzw6kZEBOJfq4,2384
145
146
  reflex/components/el/elements/typography.pyi,sha256=I67RXQhC_o_5wqjkkT3geVbAjS6MMZfnKdBPp6TzBAc,151206
147
+ reflex/components/el/pyi_hashes.json,sha256=DvaUJSm5jZgPMP6by77BzzQ5-BBVEzu0_anVoIwM3K0,63
146
148
  reflex/components/gridjs/__init__.py,sha256=xJwDm1AZ70L5-t9LLqZwGUtDpijbf1KuMYDT-j8g3pM,88
147
149
  reflex/components/gridjs/datatable.py,sha256=Fjd605rDMvZinMfWjefUwv_eOr33OeWvalOrQWkFhY4,4202
148
150
  reflex/components/gridjs/datatable.pyi,sha256=Juv16lMY60cWqSjM7RzPHQIo6MhUYiv9TrcEuulyG8A,4955
@@ -365,7 +367,7 @@ reflex/page.py,sha256=lbI5Sd4RzZadPV6cYBSNRDIlNlRwEnOv1snF2RGKH04,2392
365
367
  reflex/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
366
368
  reflex/reflex.py,sha256=O1TKYq4HdGLdVOP9X6zG7jtrux77yExBVkGOnMYjjCQ,19380
367
369
  reflex/route.py,sha256=nn_hJwtQdjiqH_dHXfqMGWKllnyPQZTSR-KWdHDhoOs,4210
368
- reflex/state.py,sha256=Mw1Bd7p61LDEqFUEFl0CqBwm6rzKayA06wo2IjeYpdU,140394
370
+ reflex/state.py,sha256=xN7jjZfqFKg2vgoLv5FvTuyz117P1sZEz0ZhEmC5emo,141073
369
371
  reflex/style.py,sha256=VZvLiBq0KEznu5AdYEQbjy3BUmiscTrGABUbDfiMlHo,13045
370
372
  reflex/testing.py,sha256=NukmgpkB70naGllLWBQTqm8XE2XBUxkpywBYFCpMwyc,35762
371
373
  reflex/utils/__init__.py,sha256=y-AHKiRQAhk2oAkvn7W8cRVTZVK625ff8tTwvZtO7S4,24
@@ -382,7 +384,7 @@ reflex/utils/imports.py,sha256=8lTJ8qCJlMUlQnZssOv0l2nntuTfGfLsLqkJAS5JTbA,3974
382
384
  reflex/utils/lazy_loader.py,sha256=-3DcwIqHNft2fb1ikgDYAMiEwNfbiWfrTBAf1gEVX2o,1367
383
385
  reflex/utils/net.py,sha256=0Yd9OLK8R_px2sqnqrDkTky6hYHtG2pEDvvilOjDfjc,1219
384
386
  reflex/utils/path_ops.py,sha256=Sio_pZ9-dqu6pAPUkO_JA9ONXDsyLGKWOVRoA-dCrec,7903
385
- reflex/utils/prerequisites.py,sha256=vEZR0Y99WKU4pEFnPTUFdRR2xnSiwSJSoaDQ5Zbv5n0,66665
387
+ reflex/utils/prerequisites.py,sha256=26lc0TVBFzdVcwl_Zja95xCC2k5UKP9Qx2Nr2FrLONU,65403
386
388
  reflex/utils/processes.py,sha256=tvYVIJgxBLboCVMYLnQYeNNIFr2cwufdWNZEOxpC4qw,13527
387
389
  reflex/utils/pyi_generator.py,sha256=6BVJ1KrLH8WvfYjBVm5-zjI6-Zdhzngp5ubkixsCIl4,41240
388
390
  reflex/utils/redir.py,sha256=bmQGAgoNWwySeLRQTpoMpmKInwIOCW77wkXT61fwcj8,1868
@@ -398,8 +400,8 @@ reflex/vars/function.py,sha256=r5NFBsueqiaRkM0F1Zp2lqWYMvWBhbNwyf5F9jrEC9A,14794
398
400
  reflex/vars/number.py,sha256=a0Qq_xM3v4Lcjm8l9Yg6ESRITUOnzgWADNmfvv4tmGI,27871
399
401
  reflex/vars/object.py,sha256=jfvxtrklztDtbD2zgNVNCZZE6X6HQMB6yJHPhtb0hUo,15033
400
402
  reflex/vars/sequence.py,sha256=_A1By3COdoTt9o5WM2odYsWf1twTv8Depf0kgHLdhGQ,54276
401
- reflex-0.7.1a4.dist-info/LICENSE,sha256=dw3zLrp9f5ObD7kqS32vWfhcImfO52PMmRqvtxq_YEE,11358
402
- reflex-0.7.1a4.dist-info/METADATA,sha256=H47SWi0vfR3FkFE-cmEVtiIA-PAJh5vGoozeqA8ZU0Y,11985
403
- reflex-0.7.1a4.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
404
- reflex-0.7.1a4.dist-info/entry_points.txt,sha256=H1Z5Yat_xJfy0dRT1Frk2PkO_p41Xy7fCKlj4FcdL9o,44
405
- reflex-0.7.1a4.dist-info/RECORD,,
403
+ reflex-0.7.1a5.dist-info/LICENSE,sha256=dw3zLrp9f5ObD7kqS32vWfhcImfO52PMmRqvtxq_YEE,11358
404
+ reflex-0.7.1a5.dist-info/METADATA,sha256=iKYWqPKXEEQfhTmEoKxZ_vimelAWQTJPU_o07yx1BZQ,11985
405
+ reflex-0.7.1a5.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
406
+ reflex-0.7.1a5.dist-info/entry_points.txt,sha256=H1Z5Yat_xJfy0dRT1Frk2PkO_p41Xy7fCKlj4FcdL9o,44
407
+ reflex-0.7.1a5.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.0.1
2
+ Generator: poetry-core 2.1.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any