65
65
"Form" ,
66
66
"ScreenDataRef" ,
67
67
"ComponentRef" ,
68
+ "FlowStr" ,
68
69
"TextHeading" ,
69
70
"TextSubheading" ,
70
71
"TextBody" ,
@@ -1446,9 +1447,10 @@ class ComponentType(utils.StrEnum):
1446
1447
NAVIGATION_LIST = "NavigationList"
1447
1448
1448
1449
1449
- class _Expr :
1450
+ class _Expr ( abc . ABC ) :
1450
1451
"""Base for refs, conditions, and expressions"""
1451
1452
1453
+ @abc .abstractmethod
1452
1454
def to_str (self ) -> str : ...
1453
1455
1454
1456
def __str__ (self ) -> str :
@@ -1468,7 +1470,7 @@ def _format_value(val: _Expr | bool | int | float | str) -> str:
1468
1470
return str (val )
1469
1471
1470
1472
1471
- class _Math (_Expr ):
1473
+ class _Math (_Expr , abc . ABC ):
1472
1474
"""Base for math expressions"""
1473
1475
1474
1476
def _to_math (self , left : _MathT , operator : str , right : _MathT ) -> MathExpression :
@@ -1507,7 +1509,7 @@ def __rmod__(self: Ref | MathExpression, other: _MathT) -> MathExpression:
1507
1509
return self ._to_math (other , "%" , self )
1508
1510
1509
1511
1510
- class _Combine (_Expr ):
1512
+ class _Combine (_Expr , abc . ABC ):
1511
1513
""" "Base for combining refs and conditions"""
1512
1514
1513
1515
def _get_left_right (
@@ -1788,6 +1790,60 @@ def __init__(self, component_name: str, screen: Screen | str | None = None):
1788
1790
super ().__init__ (prefix = "form" , field = component_name , screen = screen )
1789
1791
1790
1792
1793
+ class FlowStr (_Expr ):
1794
+ """
1795
+ Dynamic string that uses variables and math expressions. This is a helper class to avoid all the
1796
+ escaping and wrapping with quotes when using string concatenation.
1797
+
1798
+ - Added in v6.0.
1799
+
1800
+ Example::
1801
+
1802
+ >>> FlowJSON(
1803
+ ... screens=[
1804
+ ... Screen(
1805
+ ... id='START',
1806
+ ... layout=Layout(children=[
1807
+ ... age := TextInput(name='age', input_type=InputType.NUMBER),
1808
+ ... email := TextInput(name='email', input_type=InputType.EMAIL),
1809
+ ... TextHeading(text=FlowStr("Your age is {age} and your email is {email}", age=age.ref, email=email.ref), ...)
1810
+ ... ])
1811
+ ... )
1812
+ ... ]
1813
+ ... )
1814
+
1815
+ >>> FlowJSON(
1816
+ ... screens=[
1817
+ ... Screen(
1818
+ ... id='START',
1819
+ ... layout=Layout(children=[
1820
+ ... bill := TextInput(name='bill', input_type=InputType.NUMBER),
1821
+ ... tip := TextInput(name='tip', input_type=InputType.NUMBER),
1822
+ ... TextHeading(text=FlowStr("Your total bill is {bill}", bill=bill.ref + (bill.ref * tip.ref / 100)), ...)
1823
+ ... ])
1824
+ ... )
1825
+ ... ]
1826
+ ... )
1827
+
1828
+ """
1829
+
1830
+ def __init__ (self , string : str , ** variables : Ref | MathExpression ):
1831
+ """
1832
+ Initialize the dynamic string.
1833
+
1834
+ Args:
1835
+ string: The string with placeholders for the variables.
1836
+ **variables: The variables to replace in the string.
1837
+ """
1838
+ self .string = string
1839
+ self .variables = variables
1840
+
1841
+ def to_str (self ) -> str :
1842
+ escaped = re .sub (r"(?<!\\)([`'])" , r"\\\\\1" , self .string )
1843
+ wrapped = re .sub (r"([^{}]+)(?=\{|$)" , r" '\1' " , escaped )
1844
+ return f"`{ wrapped .format (** self .variables )} `"
1845
+
1846
+
1791
1847
@dataclasses .dataclass (slots = True , kw_only = True )
1792
1848
class Form (Component ):
1793
1849
"""
@@ -1861,7 +1917,7 @@ def name(self) -> str: ...
1861
1917
1862
1918
@property
1863
1919
@abc .abstractmethod
1864
- def label (self ) -> str | ScreenDataRef | ComponentRef : ...
1920
+ def label (self ) -> str | ScreenDataRef | ComponentRef | FlowStr : ...
1865
1921
1866
1922
@property
1867
1923
@abc .abstractmethod
@@ -1941,7 +1997,7 @@ class TextComponent(Component, abc.ABC):
1941
1997
1942
1998
@property
1943
1999
@abc .abstractmethod
1944
- def text (self ) -> str | ScreenDataRef | ComponentRef : ...
2000
+ def text (self ) -> str | ScreenDataRef | ComponentRef | FlowStr : ...
1945
2001
1946
2002
1947
2003
class FontWeight (utils .StrEnum ):
@@ -1980,7 +2036,7 @@ class TextHeading(TextComponent):
1980
2036
type : ComponentType = dataclasses .field (
1981
2037
default = ComponentType .TEXT_HEADING , init = False , repr = False
1982
2038
)
1983
- text : str | ScreenDataRef | ComponentRef
2039
+ text : str | ScreenDataRef | ComponentRef | FlowStr
1984
2040
visible : bool | str | Condition | ScreenDataRef | ComponentRef | None = None
1985
2041
1986
2042
@@ -2003,7 +2059,7 @@ class TextSubheading(TextComponent):
2003
2059
type : ComponentType = dataclasses .field (
2004
2060
default = ComponentType .TEXT_SUBHEADING , init = False , repr = False
2005
2061
)
2006
- text : str | ScreenDataRef | ComponentRef
2062
+ text : str | ScreenDataRef | ComponentRef | FlowStr
2007
2063
visible : bool | str | Condition | ScreenDataRef | ComponentRef | None = None
2008
2064
2009
2065
@@ -2034,7 +2090,7 @@ class TextBody(TextComponent):
2034
2090
type : ComponentType = dataclasses .field (
2035
2091
default = ComponentType .TEXT_BODY , init = False , repr = False
2036
2092
)
2037
- text : str | Iterable [str ] | ScreenDataRef | ComponentRef
2093
+ text : str | Iterable [str | FlowStr ] | ScreenDataRef | ComponentRef | FlowStr
2038
2094
markdown : bool | None = None
2039
2095
font_weight : FontWeight | str | ScreenDataRef | ComponentRef | None = None
2040
2096
strikethrough : bool | str | ScreenDataRef | ComponentRef | None = None
@@ -2068,7 +2124,7 @@ class TextCaption(TextComponent):
2068
2124
type : ComponentType = dataclasses .field (
2069
2125
default = ComponentType .TEXT_CAPTION , init = False , repr = False
2070
2126
)
2071
- text : str | Iterable [str ] | ScreenDataRef | ComponentRef
2127
+ text : str | Iterable [str | FlowStr ] | ScreenDataRef | ComponentRef | FlowStr
2072
2128
markdown : bool | None = None
2073
2129
font_weight : FontWeight | str | ScreenDataRef | ComponentRef | None = None
2074
2130
strikethrough : bool | str | ScreenDataRef | ComponentRef | None = None
@@ -2119,7 +2175,7 @@ class RichText(TextComponent):
2119
2175
type : ComponentType = dataclasses .field (
2120
2176
default = ComponentType .RICH_TEXT , init = False , repr = False
2121
2177
)
2122
- text : str | Iterable [str ] | ScreenDataRef | ComponentRef
2178
+ text : str | Iterable [str | FlowStr ] | ScreenDataRef | ComponentRef | FlowStr
2123
2179
visible : bool | str | Condition | ScreenDataRef | ComponentRef | None = None
2124
2180
2125
2181
@@ -2132,7 +2188,7 @@ class TextEntryComponent(FormComponent, abc.ABC):
2132
2188
2133
2189
@property
2134
2190
@abc .abstractmethod
2135
- def helper_text (self ) -> str | ScreenDataRef | ComponentRef | None : ...
2191
+ def helper_text (self ) -> str | ScreenDataRef | ComponentRef | FlowStr | None : ...
2136
2192
2137
2193
@property
2138
2194
@abc .abstractmethod
@@ -2201,13 +2257,13 @@ class TextInput(TextEntryComponent):
2201
2257
default = ComponentType .TEXT_INPUT , init = False , repr = False
2202
2258
)
2203
2259
name : str
2204
- label : str | ScreenDataRef | ComponentRef
2260
+ label : str | ScreenDataRef | ComponentRef | FlowStr
2205
2261
input_type : InputType | str | ScreenDataRef | ComponentRef | None = None
2206
2262
pattern : str | re .Pattern | ScreenDataRef | ComponentRef | None = None
2207
2263
required : bool | str | ScreenDataRef | ComponentRef | None = None
2208
2264
min_chars : int | str | ScreenDataRef | ComponentRef | None = None
2209
2265
max_chars : int | str | ScreenDataRef | ComponentRef | None = None
2210
- helper_text : str | ScreenDataRef | ComponentRef | None = None
2266
+ helper_text : str | ScreenDataRef | ComponentRef | FlowStr | None = None
2211
2267
enabled : bool | str | ScreenDataRef | ComponentRef | None = None
2212
2268
visible : bool | str | Condition | ScreenDataRef | ComponentRef | None = None
2213
2269
init_value : str | ScreenDataRef | ComponentRef | None = None
@@ -2248,10 +2304,10 @@ class TextArea(TextEntryComponent):
2248
2304
default = ComponentType .TEXT_AREA , init = False , repr = False
2249
2305
)
2250
2306
name : str
2251
- label : str | ScreenDataRef | ComponentRef
2307
+ label : str | ScreenDataRef | ComponentRef | FlowStr
2252
2308
required : bool | str | ScreenDataRef | ComponentRef | None = None
2253
2309
max_length : int | str | ScreenDataRef | ComponentRef | None = None
2254
- helper_text : str | ScreenDataRef | ComponentRef | None = None
2310
+ helper_text : str | ScreenDataRef | ComponentRef | FlowStr | None = None
2255
2311
enabled : bool | str | ScreenDataRef | ComponentRef | None = None
2256
2312
visible : bool | str | Condition | ScreenDataRef | ComponentRef | None = None
2257
2313
init_value : str | ScreenDataRef | ComponentRef | None = None
@@ -2316,8 +2372,8 @@ class CheckboxGroup(FormComponent):
2316
2372
)
2317
2373
name : str
2318
2374
data_source : Iterable [DataSource ] | str | ScreenDataRef | ComponentRef
2319
- label : str | ScreenDataRef | ComponentRef | None = None
2320
- description : str | ScreenDataRef | ComponentRef | None = None
2375
+ label : str | ScreenDataRef | ComponentRef | FlowStr | None = None
2376
+ description : str | ScreenDataRef | ComponentRef | FlowStr | None = None
2321
2377
min_selected_items : int | str | ScreenDataRef | ComponentRef | None = None
2322
2378
max_selected_items : int | str | ScreenDataRef | ComponentRef | None = None
2323
2379
required : bool | str | ScreenDataRef | ComponentRef | None = None
@@ -2370,8 +2426,8 @@ class RadioButtonsGroup(FormComponent):
2370
2426
)
2371
2427
name : str
2372
2428
data_source : Iterable [DataSource ] | str | ScreenDataRef | ComponentRef
2373
- label : str | ScreenDataRef | ComponentRef | None = None
2374
- description : str | ScreenDataRef | ComponentRef | None = None
2429
+ label : str | ScreenDataRef | ComponentRef | FlowStr | None = None
2430
+ description : str | ScreenDataRef | ComponentRef | FlowStr | None = None
2375
2431
required : bool | str | ScreenDataRef | ComponentRef | None = None
2376
2432
visible : bool | str | Condition | ScreenDataRef | ComponentRef | None = None
2377
2433
enabled : bool | str | ScreenDataRef | ComponentRef | None = None
@@ -2419,7 +2475,7 @@ class Dropdown(FormComponent):
2419
2475
default = ComponentType .DROPDOWN , init = False , repr = False
2420
2476
)
2421
2477
name : str
2422
- label : str | ScreenDataRef | ComponentRef
2478
+ label : str | ScreenDataRef | ComponentRef | FlowStr
2423
2479
data_source : Iterable [DataSource ] | str | ScreenDataRef | ComponentRef
2424
2480
enabled : bool | str | ScreenDataRef | ComponentRef | None = None
2425
2481
required : bool | str | ScreenDataRef | ComponentRef | None = None
@@ -2449,11 +2505,11 @@ class Footer(Component):
2449
2505
default = ComponentType .FOOTER , init = False , repr = False
2450
2506
)
2451
2507
visible : None = dataclasses .field (default = None , init = False , repr = False )
2452
- label : str | ScreenDataRef | ComponentRef
2508
+ label : str | ScreenDataRef | ComponentRef | FlowStr
2453
2509
on_click_action : CompleteAction | DataExchangeAction | NavigateAction
2454
- left_caption : str | ScreenDataRef | ComponentRef | None = None
2455
- center_caption : str | ScreenDataRef | ComponentRef | None = None
2456
- right_caption : str | ScreenDataRef | ComponentRef | None = None
2510
+ left_caption : str | ScreenDataRef | ComponentRef | FlowStr | None = None
2511
+ center_caption : str | ScreenDataRef | ComponentRef | FlowStr | None = None
2512
+ right_caption : str | ScreenDataRef | ComponentRef | FlowStr | None = None
2457
2513
enabled : bool | str | ScreenDataRef | ComponentRef | None = None
2458
2514
2459
2515
@@ -2489,7 +2545,7 @@ class OptIn(FormComponent):
2489
2545
)
2490
2546
enabled : None = dataclasses .field (default = None , init = False , repr = False )
2491
2547
name : str
2492
- label : str | ScreenDataRef | ComponentRef
2548
+ label : str | ScreenDataRef | ComponentRef | FlowStr
2493
2549
required : bool | str | ScreenDataRef | ComponentRef | None = None
2494
2550
visible : bool | str | Condition | ScreenDataRef | ComponentRef | None = None
2495
2551
init_value : bool | str | ScreenDataRef | ComponentRef | None = None
@@ -2526,7 +2582,7 @@ class EmbeddedLink(Component):
2526
2582
type : ComponentType = dataclasses .field (
2527
2583
default = ComponentType .EMBEDDED_LINK , init = False , repr = False
2528
2584
)
2529
- text : str | ScreenDataRef | ComponentRef
2585
+ text : str | ScreenDataRef | ComponentRef | FlowStr
2530
2586
on_click_action : (
2531
2587
DataExchangeAction | UpdateDataAction | NavigateAction | OpenUrlAction
2532
2588
)
@@ -2578,8 +2634,8 @@ class NavigationList(Component):
2578
2634
visible : None = dataclasses .field (default = None , init = False , repr = False )
2579
2635
name : str
2580
2636
list_items : Iterable [NavigationItem ] | ScreenDataRef | ComponentRef | str
2581
- label : str | ScreenDataRef | ComponentRef | None = None
2582
- description : str | ScreenDataRef | ComponentRef | None = None
2637
+ label : str | ScreenDataRef | ComponentRef | FlowStr | None = None
2638
+ description : str | ScreenDataRef | ComponentRef | FlowStr | None = None
2583
2639
media_size : MediaSize | str | ScreenDataRef | ComponentRef | None = None
2584
2640
on_click_action : NavigateAction | DataExchangeAction | None = None
2585
2641
@@ -2721,13 +2777,13 @@ class DatePicker(FormComponent):
2721
2777
default = ComponentType .DATE_PICKER , init = False , repr = False
2722
2778
)
2723
2779
name : str
2724
- label : str | ScreenDataRef | ComponentRef
2780
+ label : str | ScreenDataRef | ComponentRef | FlowStr
2725
2781
min_date : datetime .date | str | ScreenDataRef | ComponentRef | None = None
2726
2782
max_date : datetime .date | str | ScreenDataRef | ComponentRef | None = None
2727
2783
unavailable_dates : (
2728
2784
Iterable [datetime .date | str ] | str | ScreenDataRef | ComponentRef | None
2729
2785
) = None
2730
- helper_text : str | ScreenDataRef | ComponentRef | None = None
2786
+ helper_text : str | ScreenDataRef | ComponentRef | FlowStr | None = None
2731
2787
enabled : bool | str | ScreenDataRef | ComponentRef | None = None
2732
2788
required : bool | str | ScreenDataRef | ComponentRef | None = None
2733
2789
visible : bool | str | Condition | ScreenDataRef | ComponentRef | None = None
@@ -2822,8 +2878,8 @@ class CalendarPicker(FormComponent):
2822
2878
default = ComponentType .CALENDAR_PICKER , init = False , repr = False
2823
2879
)
2824
2880
name : str
2825
- title : str | ScreenDataRef | ComponentRef | None = None
2826
- description : str | ScreenDataRef | ComponentRef | None = None
2881
+ title : str | ScreenDataRef | ComponentRef | FlowStr | None = None
2882
+ description : str | ScreenDataRef | ComponentRef | FlowStr | None = None
2827
2883
label : (
2828
2884
dict [Literal ["start-date" , "end-date" ], str ]
2829
2885
| str
@@ -2846,6 +2902,7 @@ class CalendarPicker(FormComponent):
2846
2902
| str
2847
2903
| ScreenDataRef
2848
2904
| ComponentRef
2905
+ | FlowStr
2849
2906
| None
2850
2907
) = None
2851
2908
enabled : bool | str | ScreenDataRef | ComponentRef | None = None
@@ -2995,8 +3052,8 @@ class PhotoPicker(FormComponent):
2995
3052
required : None = dataclasses .field (default = None , init = False , repr = False )
2996
3053
init_value : None = dataclasses .field (default = None , init = False , repr = False )
2997
3054
name : str
2998
- label : str | ScreenDataRef | ComponentRef
2999
- description : str | ScreenDataRef | ComponentRef | None = None
3055
+ label : str | ScreenDataRef | ComponentRef | FlowStr
3056
+ description : str | ScreenDataRef | ComponentRef | FlowStr | None = None
3000
3057
photo_source : PhotoSource | str | ScreenDataRef | ComponentRef | None = None
3001
3058
max_file_size_kb : int | str | ScreenDataRef | ComponentRef | None = None
3002
3059
min_uploaded_photos : int | str | ScreenDataRef | ComponentRef | None = None
@@ -3048,8 +3105,8 @@ class DocumentPicker(FormComponent):
3048
3105
required : None = dataclasses .field (default = None , init = False , repr = False )
3049
3106
init_value : None = dataclasses .field (default = None , init = False , repr = False )
3050
3107
name : str
3051
- label : str | ScreenDataRef | ComponentRef
3052
- description : str | ScreenDataRef | ComponentRef | None = None
3108
+ label : str | ScreenDataRef | ComponentRef | FlowStr
3109
+ description : str | ScreenDataRef | ComponentRef | FlowStr | None = None
3053
3110
max_file_size_kb : int | str | ScreenDataRef | ComponentRef | None = None
3054
3111
min_uploaded_documents : int | str | ScreenDataRef | ComponentRef | None = None
3055
3112
max_uploaded_documents : int | str | ScreenDataRef | ComponentRef | None = None
0 commit comments