소스 검색

Handle python `range` passed to rx.Var.create (#4716)

* Handle python `range` passed to rx.Var.create

Fix the range function to use Math.ceil to handle jagged steps.

Update test cases.

* Set ToVarOperation.__qualname__ for better repr
Masen Furer 3 달 전
부모
커밋
fc16bed7ca
4개의 변경된 파일25개의 추가작업 그리고 7개의 파일을 삭제
  1. 10 2
      reflex/vars/base.py
  2. 1 1
      reflex/vars/sequence.py
  3. 10 0
      tests/integration/test_var_operations.py
  4. 4 4
      tests/units/test_var.py

+ 10 - 2
reflex/vars/base.py

@@ -445,7 +445,12 @@ class Var(Generic[VAR_TYPE]):
 
                 _default_var_type: ClassVar[GenericType] = default_type
 
-            ToVarOperation.__name__ = f'To{cls.__name__.removesuffix("Var")}Operation'
+            new_to_var_operation_name = f"To{cls.__name__.removesuffix('Var')}Operation"
+            ToVarOperation.__qualname__ = (
+                ToVarOperation.__qualname__.removesuffix(ToVarOperation.__name__)
+                + new_to_var_operation_name
+            )
+            ToVarOperation.__name__ = new_to_var_operation_name
 
             _var_subclasses.append(VarSubclassEntry(cls, ToVarOperation, python_types))
 
@@ -1385,7 +1390,7 @@ class LiteralVar(Var):
             TypeError: If the value is not a supported type for LiteralVar.
         """
         from .object import LiteralObjectVar
-        from .sequence import LiteralStringVar
+        from .sequence import ArrayVar, LiteralStringVar
 
         if isinstance(value, Var):
             if _var_data is None:
@@ -1441,6 +1446,9 @@ class LiteralVar(Var):
                 _var_data=_var_data,
             )
 
+        if isinstance(value, range):
+            return ArrayVar.range(value.start, value.stop, value.step)
+
         raise TypeError(
             f"Unsupported type {type(value)} for LiteralVar. Tried to create a LiteralVar from {value}."
         )

+ 1 - 1
reflex/vars/sequence.py

@@ -1593,7 +1593,7 @@ def array_range_operation(
         The range of numbers.
     """
     return var_operation_return(
-        js_expression=f"Array.from({{ length: ({stop!s} - {start!s}) / {step!s} }}, (_, i) => {start!s} + i * {step!s})",
+        js_expression=f"Array.from({{ length: Math.ceil(({stop!s} - {start!s}) / {step!s}) }}, (_, i) => {start!s} + i * {step!s})",
         var_type=List[int],
     )
 

+ 10 - 0
tests/integration/test_var_operations.py

@@ -600,6 +600,11 @@ def VarOperations():
                 ),
                 id="foreach_in_match",
             ),
+            # Literal range var in a foreach
+            rx.box(rx.foreach(range(42, 80, 27), rx.text.span), id="range_in_foreach1"),
+            rx.box(rx.foreach(range(42, 80, 3), rx.text.span), id="range_in_foreach2"),
+            rx.box(rx.foreach(range(42, 20, -6), rx.text.span), id="range_in_foreach3"),
+            rx.box(rx.foreach(range(42, 43, 5), rx.text.span), id="range_in_foreach4"),
         )
 
 
@@ -799,6 +804,11 @@ def test_var_operations(driver, var_operations: AppHarness):
         ("memo_comp_nested", "345"),
         # foreach in a match
         ("foreach_in_match", "first\nsecond\nthird"),
+        # literal range in a foreach
+        ("range_in_foreach1", "4269"),
+        ("range_in_foreach2", "42454851545760636669727578"),
+        ("range_in_foreach3", "42363024"),
+        ("range_in_foreach4", "42"),
     ]
 
     for tag, expected in tests:

+ 4 - 4
tests/units/test_var.py

@@ -1076,19 +1076,19 @@ def test_array_operations():
     assert str(array_var.reverse()) == "[1, 2, 3, 4, 5].slice().reverse()"
     assert (
         str(ArrayVar.range(10))
-        == "Array.from({ length: (10 - 0) / 1 }, (_, i) => 0 + i * 1)"
+        == "Array.from({ length: Math.ceil((10 - 0) / 1) }, (_, i) => 0 + i * 1)"
     )
     assert (
         str(ArrayVar.range(1, 10))
-        == "Array.from({ length: (10 - 1) / 1 }, (_, i) => 1 + i * 1)"
+        == "Array.from({ length: Math.ceil((10 - 1) / 1) }, (_, i) => 1 + i * 1)"
     )
     assert (
         str(ArrayVar.range(1, 10, 2))
-        == "Array.from({ length: (10 - 1) / 2 }, (_, i) => 1 + i * 2)"
+        == "Array.from({ length: Math.ceil((10 - 1) / 2) }, (_, i) => 1 + i * 2)"
     )
     assert (
         str(ArrayVar.range(1, 10, -1))
-        == "Array.from({ length: (10 - 1) / -1 }, (_, i) => 1 + i * -1)"
+        == "Array.from({ length: Math.ceil((10 - 1) / -1) }, (_, i) => 1 + i * -1)"
     )