فهرست منبع

add `,` and `_` operations (#4950)

* add `,` and `_` operations

* add tests
Khaleel Al-Adhami 2 ماه پیش
والد
کامیت
1ac8f0272d
3فایلهای تغییر یافته به همراه117 افزوده شده و 19 حذف شده
  1. 19 19
      reflex/vars/number.py
  2. 37 0
      reflex/vars/sequence.py
  3. 61 0
      tests/integration/test_var_operations.py

+ 19 - 19
reflex/vars/number.py

@@ -546,6 +546,20 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
         Raises:
             VarValueError: If the format specifier is not supported.
         """
+        from .sequence import (
+            get_decimal_string_operation,
+            get_decimal_string_separator_operation,
+        )
+
+        separator = ""
+
+        if format_spec and format_spec[:1] == ",":
+            separator = ","
+            format_spec = format_spec[1:]
+        elif format_spec and format_spec[:1] == "_":
+            separator = "_"
+            format_spec = format_spec[1:]
+
         if (
             format_spec
             and format_spec[-1] == "f"
@@ -553,14 +567,17 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
             and format_spec[1:-1].isdigit()
         ):
             how_many_decimals = int(format_spec[1:-1])
+            return f"{get_decimal_string_operation(self, Var.create(how_many_decimals), Var.create(separator))}"
+
+        if not format_spec and separator:
             return (
-                f"{get_decimal_string_operation(self, Var.create(how_many_decimals))}"
+                f"{get_decimal_string_separator_operation(self, Var.create(separator))}"
             )
 
         if format_spec:
             raise VarValueError(
                 (
-                    "Unknown format code '{}' for object of type 'NumberVar'. It is only supported to use '.f' for float numbers."
+                    "Unknown format code '{}' for object of type 'NumberVar'. It is only supported to use ',', '_', and '.f' for float numbers."
                     "If possible, use computed variables instead: https://reflex.dev/docs/vars/computed-vars/"
                 ).format(format_spec)
             )
@@ -568,23 +585,6 @@ class NumberVar(Var[NUMBER_T], python_types=(int, float)):
         return super().__format__(format_spec)
 
 
-@var_operation
-def get_decimal_string_operation(value: NumberVar, decimals: NumberVar):
-    """Get the decimal string of the number.
-
-    Args:
-        value: The number.
-        decimals: The number of decimals.
-
-    Returns:
-        The decimal string of the number.
-    """
-    return var_operation_return(
-        js_expression=f"({value}.toFixed({decimals}))",
-        var_type=str,
-    )
-
-
 def binary_number_operation(
     func: Callable[[NumberVar, NumberVar], str],
 ) -> Callable[[number_types, number_types], NumberVar]:

+ 37 - 0
reflex/vars/sequence.py

@@ -1202,6 +1202,43 @@ def string_replace_operation(
     )
 
 
+@var_operation
+def get_decimal_string_separator_operation(value: NumberVar, separator: StringVar):
+    """Get the decimal string separator.
+
+    Args:
+        value: The number.
+        separator: The separator.
+
+    Returns:
+        The decimal string separator.
+    """
+    return var_operation_return(
+        js_expression=f"({value}.toLocaleString('en-US').replaceAll(',', {separator}))",
+        var_type=str,
+    )
+
+
+@var_operation
+def get_decimal_string_operation(
+    value: NumberVar, decimals: NumberVar, separator: StringVar
+):
+    """Get the decimal string of the number.
+
+    Args:
+        value: The number.
+        decimals: The number of decimals.
+        separator: The separator.
+
+    Returns:
+        The decimal string of the number.
+    """
+    return var_operation_return(
+        js_expression=f"({value}.toLocaleString('en-US', ((decimals) => ({{minimumFractionDigits: decimals, maximumFractionDigits: decimals}}))({decimals})).replaceAll(',', {separator}))",
+        var_type=str,
+    )
+
+
 # Compile regex for finding reflex var tags.
 _decode_var_pattern_re = (
     rf"{constants.REFLEX_VAR_OPENING_TAG}(.*?){constants.REFLEX_VAR_CLOSING_TAG}"

+ 61 - 0
tests/integration/test_var_operations.py

@@ -665,6 +665,54 @@ def VarOperations():
                 rx.foreach(VarOperationState.optional_dict_value, rx.text.span),
                 id="optional_dict_value",
             ),
+            rx.box(
+                rx.text.span(f"{rx.Var.create(13212312312.1231231)}"),
+                id="float_format",
+            ),
+            rx.box(
+                rx.text.span(f"{rx.Var.create(13212312312.1231231):.0f}"),
+                id="float_format_0f",
+            ),
+            rx.box(
+                rx.text.span(f"{rx.Var.create(13212312312.1231231):.1f}"),
+                id="float_format_1f",
+            ),
+            rx.box(
+                rx.text.span(f"{rx.Var.create(13212312312.1231231):.2f}"),
+                id="float_format_2f",
+            ),
+            rx.box(
+                rx.text.span(f"{rx.Var.create(13212312312.1231231):,}"),
+                id="float_format_comma",
+            ),
+            rx.box(
+                rx.text.span(f"{rx.Var.create(13212312312.1231231):_}"),
+                id="float_format_underscore",
+            ),
+            rx.box(
+                rx.text.span(f"{rx.Var.create(13212312312.1231231):,.0f}"),
+                id="float_format_comma_0f",
+            ),
+            rx.box(
+                rx.text.span(f"{rx.Var.create(13212312312.1231231):,.1f}"),
+                id="float_format_comma_1f",
+            ),
+            rx.box(
+                rx.text.span(f"{rx.Var.create(13212312312.1231231):,.2f}"),
+                id="float_format_comma_2f",
+            ),
+            rx.box(
+                rx.text.span(f"{rx.Var.create(13212312312.1231231):_.0f}"),
+                id="float_format_underscore_0f",
+            ),
+            rx.box(
+                rx.text.span(f"{rx.Var.create(13212312312.1231231):_.1f}"),
+                id="float_format_underscore_1f",
+            ),
+            rx.box(
+                rx.text.span(f"{rx.Var.create(13212312312.1231231):_.2f}"),
+                id="float_format_underscore_2f",
+            ),
         )
 
 
@@ -875,6 +923,19 @@ def test_var_operations(driver, var_operations: AppHarness):
         ("str_in_foreach", "a b c d e f"),
         ("str_var_in_foreach", "f i r s t"),
         ("typed_dict_in_foreach", "Hello Alice33Hello Bob28"),
+        # fstring operations
+        ("float_format", "13212312312.123123"),
+        ("float_format_0f", "13212312312"),
+        ("float_format_1f", "13212312312.1"),
+        ("float_format_2f", "13212312312.12"),
+        ("float_format_comma", "13,212,312,312.123"),
+        ("float_format_underscore", "13_212_312_312.123"),
+        ("float_format_comma_0f", "13,212,312,312"),
+        ("float_format_comma_1f", "13,212,312,312.1"),
+        ("float_format_comma_2f", "13,212,312,312.12"),
+        ("float_format_underscore_0f", "13_212_312_312"),
+        ("float_format_underscore_1f", "13_212_312_312.1"),
+        ("float_format_underscore_2f", "13_212_312_312.12"),
     ]
 
     for tag, expected in tests: