reflex 0.5.10a2__py3-none-any.whl → 0.6.0__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.
- reflex/.templates/jinja/custom_components/pyproject.toml.jinja2 +2 -2
- reflex/.templates/jinja/web/pages/_app.js.jinja2 +1 -1
- reflex/.templates/jinja/web/pages/utils.js.jinja2 +4 -4
- reflex/.templates/jinja/web/utils/context.js.jinja2 +1 -1
- reflex/.templates/jinja/web/utils/theme.js.jinja2 +1 -1
- reflex/.templates/web/utils/state.js +3 -1
- reflex/__init__.py +10 -3
- reflex/__init__.pyi +3 -2
- reflex/app.py +47 -11
- reflex/app_module_for_backend.py +1 -1
- reflex/base.py +3 -2
- reflex/compiler/compiler.py +5 -5
- reflex/compiler/utils.py +5 -3
- reflex/components/base/app_wrap.py +2 -4
- reflex/components/base/app_wrap.pyi +16 -26
- reflex/components/base/bare.py +6 -4
- reflex/components/base/body.pyi +16 -26
- reflex/components/base/document.pyi +76 -126
- reflex/components/base/error_boundary.py +9 -8
- reflex/components/base/error_boundary.pyi +18 -30
- reflex/components/base/fragment.pyi +16 -26
- reflex/components/base/head.pyi +31 -51
- reflex/components/base/link.py +1 -1
- reflex/components/base/link.pyi +31 -51
- reflex/components/base/meta.pyi +61 -101
- reflex/components/base/script.py +2 -2
- reflex/components/base/script.pyi +20 -36
- reflex/components/component.py +107 -130
- reflex/components/core/banner.py +61 -66
- reflex/components/core/banner.pyi +129 -230
- reflex/components/core/client_side_routing.py +2 -2
- reflex/components/core/client_side_routing.pyi +31 -51
- reflex/components/core/clipboard.py +4 -3
- reflex/components/core/clipboard.pyi +19 -31
- reflex/components/core/cond.py +21 -44
- reflex/components/core/debounce.py +7 -9
- reflex/components/core/debounce.pyi +19 -31
- reflex/components/core/foreach.py +4 -14
- reflex/components/core/html.py +1 -1
- reflex/components/core/html.pyi +34 -44
- reflex/components/core/match.py +36 -43
- reflex/components/core/upload.py +27 -26
- reflex/components/core/upload.pyi +81 -116
- reflex/components/datadisplay/code.py +55 -29
- reflex/components/datadisplay/code.pyi +303 -410
- reflex/components/datadisplay/dataeditor.py +13 -9
- reflex/components/datadisplay/dataeditor.pyi +39 -51
- reflex/components/el/__init__.py +0 -1
- reflex/components/el/__init__.pyi +0 -11
- reflex/components/el/element.pyi +16 -26
- reflex/components/el/elements/__init__.py +1 -7
- reflex/components/el/elements/__init__.pyi +1 -15
- reflex/components/el/elements/base.py +1 -1
- reflex/components/el/elements/base.pyi +33 -43
- reflex/components/el/elements/forms.py +26 -33
- reflex/components/el/elements/forms.pyi +542 -694
- reflex/components/el/elements/inline.py +1 -1
- reflex/components/el/elements/inline.pyi +909 -1189
- reflex/components/el/elements/media.py +1 -22
- reflex/components/el/elements/media.pyi +765 -975
- reflex/components/el/elements/metadata.py +3 -5
- reflex/components/el/elements/metadata.pyi +175 -235
- reflex/components/el/elements/other.py +1 -1
- reflex/components/el/elements/other.pyi +228 -298
- reflex/components/el/elements/scripts.py +1 -1
- reflex/components/el/elements/scripts.pyi +106 -136
- reflex/components/el/elements/sectioning.py +0 -2
- reflex/components/el/elements/sectioning.pyi +481 -631
- reflex/components/el/elements/tables.py +1 -1
- reflex/components/el/elements/tables.pyi +341 -441
- reflex/components/el/elements/typography.py +1 -1
- reflex/components/el/elements/typography.pyi +491 -641
- reflex/components/gridjs/datatable.py +9 -13
- reflex/components/gridjs/datatable.pyi +33 -53
- reflex/components/lucide/icon.py +3 -127
- reflex/components/lucide/icon.pyi +31 -160
- reflex/components/markdown/markdown.py +32 -42
- reflex/components/markdown/markdown.pyi +28 -41
- reflex/components/moment/moment.py +13 -12
- reflex/components/moment/moment.pyi +22 -33
- reflex/components/next/base.pyi +16 -26
- reflex/components/next/image.py +1 -5
- reflex/components/next/image.pyi +21 -35
- reflex/components/next/link.py +1 -1
- reflex/components/next/link.pyi +16 -26
- reflex/components/next/video.py +1 -1
- reflex/components/next/video.pyi +16 -26
- reflex/components/plotly/plotly.py +17 -30
- reflex/components/plotly/plotly.pyi +38 -52
- reflex/components/props.py +21 -10
- reflex/components/radix/__init__.pyi +2 -1
- reflex/components/radix/primitives/accordion.py +6 -7
- reflex/components/radix/primitives/accordion.pyi +415 -485
- reflex/components/radix/primitives/base.py +1 -1
- reflex/components/radix/primitives/base.pyi +31 -51
- reflex/components/radix/primitives/drawer.py +1 -1
- reflex/components/radix/primitives/drawer.pyi +162 -262
- reflex/components/radix/primitives/form.py +1 -1
- reflex/components/radix/primitives/form.pyi +247 -353
- reflex/components/radix/primitives/progress.py +1 -1
- reflex/components/radix/primitives/progress.pyi +226 -276
- reflex/components/radix/primitives/slider.py +1 -1
- reflex/components/radix/primitives/slider.pyi +82 -132
- reflex/components/radix/themes/base.py +8 -25
- reflex/components/radix/themes/base.pyi +171 -242
- reflex/components/radix/themes/color_mode.py +11 -20
- reflex/components/radix/themes/color_mode.pyi +198 -231
- reflex/components/radix/themes/components/__init__.pyi +1 -0
- reflex/components/radix/themes/components/alert_dialog.py +1 -1
- reflex/components/radix/themes/components/alert_dialog.pyi +129 -199
- reflex/components/radix/themes/components/aspect_ratio.py +1 -1
- reflex/components/radix/themes/components/aspect_ratio.pyi +16 -26
- reflex/components/radix/themes/components/avatar.py +1 -1
- reflex/components/radix/themes/components/avatar.pyi +69 -79
- reflex/components/radix/themes/components/badge.py +1 -1
- reflex/components/radix/themes/components/badge.pyi +87 -97
- reflex/components/radix/themes/components/button.py +1 -1
- reflex/components/radix/themes/components/button.pyi +97 -107
- reflex/components/radix/themes/components/callout.py +1 -1
- reflex/components/radix/themes/components/callout.pyi +317 -367
- reflex/components/radix/themes/components/card.py +1 -1
- reflex/components/radix/themes/components/card.pyi +37 -47
- reflex/components/radix/themes/components/checkbox.py +2 -4
- reflex/components/radix/themes/components/checkbox.pyi +205 -241
- reflex/components/radix/themes/components/checkbox_cards.py +1 -1
- reflex/components/radix/themes/components/checkbox_cards.pyi +92 -112
- reflex/components/radix/themes/components/checkbox_group.py +1 -1
- reflex/components/radix/themes/components/checkbox_group.pyi +84 -104
- reflex/components/radix/themes/components/context_menu.py +1 -1
- reflex/components/radix/themes/components/context_menu.pyi +230 -310
- reflex/components/radix/themes/components/data_list.py +6 -1
- reflex/components/radix/themes/components/data_list.pyi +131 -166
- reflex/components/radix/themes/components/dialog.py +1 -1
- reflex/components/radix/themes/components/dialog.pyi +132 -202
- reflex/components/radix/themes/components/dropdown_menu.py +1 -1
- reflex/components/radix/themes/components/dropdown_menu.pyi +241 -323
- reflex/components/radix/themes/components/hover_card.py +1 -1
- reflex/components/radix/themes/components/hover_card.pyi +86 -126
- reflex/components/radix/themes/components/icon_button.py +1 -1
- reflex/components/radix/themes/components/icon_button.pyi +97 -107
- reflex/components/radix/themes/components/inset.py +1 -1
- reflex/components/radix/themes/components/inset.pyi +46 -56
- reflex/components/radix/themes/components/popover.py +1 -1
- reflex/components/radix/themes/components/popover.pyi +91 -131
- reflex/components/radix/themes/components/progress.py +1 -1
- reflex/components/radix/themes/components/progress.pyi +70 -80
- reflex/components/radix/themes/components/radio.py +1 -1
- reflex/components/radix/themes/components/radio.pyi +68 -78
- reflex/components/radix/themes/components/radio_cards.py +1 -1
- reflex/components/radix/themes/components/radio_cards.pyi +96 -116
- reflex/components/radix/themes/components/radio_group.py +32 -31
- reflex/components/radix/themes/components/radio_group.pyi +230 -266
- reflex/components/radix/themes/components/scroll_area.py +1 -1
- reflex/components/radix/themes/components/scroll_area.pyi +20 -30
- reflex/components/radix/themes/components/segmented_control.py +1 -1
- reflex/components/radix/themes/components/segmented_control.pyi +88 -110
- reflex/components/radix/themes/components/select.py +1 -1
- reflex/components/radix/themes/components/select.pyi +365 -461
- reflex/components/radix/themes/components/separator.py +2 -4
- reflex/components/radix/themes/components/separator.pyi +68 -78
- reflex/components/radix/themes/components/skeleton.py +1 -1
- reflex/components/radix/themes/components/skeleton.pyi +22 -32
- reflex/components/radix/themes/components/slider.py +1 -1
- reflex/components/radix/themes/components/slider.pyi +74 -86
- reflex/components/radix/themes/components/spinner.py +1 -1
- reflex/components/radix/themes/components/spinner.pyi +18 -28
- reflex/components/radix/themes/components/switch.py +1 -1
- reflex/components/radix/themes/components/switch.pyi +70 -82
- reflex/components/radix/themes/components/table.py +1 -1
- reflex/components/radix/themes/components/table.pyi +254 -324
- reflex/components/radix/themes/components/tabs.py +1 -1
- reflex/components/radix/themes/components/tabs.pyi +134 -188
- reflex/components/radix/themes/components/text_area.py +1 -1
- reflex/components/radix/themes/components/text_area.pyi +95 -109
- reflex/components/radix/themes/components/text_field.py +1 -80
- reflex/components/radix/themes/components/text_field.pyi +245 -290
- reflex/components/radix/themes/components/tooltip.py +1 -1
- reflex/components/radix/themes/components/tooltip.pyi +25 -35
- reflex/components/radix/themes/layout/__init__.pyi +1 -0
- reflex/components/radix/themes/layout/base.py +1 -1
- reflex/components/radix/themes/layout/base.pyi +55 -65
- reflex/components/radix/themes/layout/box.pyi +33 -43
- reflex/components/radix/themes/layout/center.pyi +55 -65
- reflex/components/radix/themes/layout/container.py +2 -4
- reflex/components/radix/themes/layout/container.pyi +35 -45
- reflex/components/radix/themes/layout/flex.py +1 -1
- reflex/components/radix/themes/layout/flex.pyi +55 -65
- reflex/components/radix/themes/layout/grid.py +1 -1
- reflex/components/radix/themes/layout/grid.pyi +63 -73
- reflex/components/radix/themes/layout/list.py +1 -1
- reflex/components/radix/themes/layout/list.pyi +188 -238
- reflex/components/radix/themes/layout/section.py +2 -4
- reflex/components/radix/themes/layout/section.pyi +35 -45
- reflex/components/radix/themes/layout/spacer.pyi +55 -65
- reflex/components/radix/themes/layout/stack.py +1 -1
- reflex/components/radix/themes/layout/stack.pyi +125 -155
- reflex/components/radix/themes/typography/blockquote.py +1 -1
- reflex/components/radix/themes/typography/blockquote.pyi +88 -98
- reflex/components/radix/themes/typography/code.py +1 -1
- reflex/components/radix/themes/typography/code.pyi +89 -99
- reflex/components/radix/themes/typography/heading.py +1 -1
- reflex/components/radix/themes/typography/heading.pyi +95 -105
- reflex/components/radix/themes/typography/link.py +1 -1
- reflex/components/radix/themes/typography/link.pyi +101 -111
- reflex/components/radix/themes/typography/text.py +1 -1
- reflex/components/radix/themes/typography/text.pyi +494 -564
- reflex/components/react_player/audio.pyi +32 -58
- reflex/components/react_player/react_player.py +1 -1
- reflex/components/react_player/react_player.pyi +32 -58
- reflex/components/react_player/video.pyi +32 -58
- reflex/components/recharts/cartesian.py +22 -19
- reflex/components/recharts/cartesian.pyi +658 -840
- reflex/components/recharts/charts.py +3 -3
- reflex/components/recharts/charts.pyi +238 -342
- reflex/components/recharts/general.py +8 -8
- reflex/components/recharts/general.pyi +175 -225
- reflex/components/recharts/polar.py +11 -11
- reflex/components/recharts/polar.pyi +135 -171
- reflex/components/recharts/recharts.pyi +31 -51
- reflex/components/sonner/toast.py +27 -31
- reflex/components/sonner/toast.pyi +36 -45
- reflex/components/suneditor/editor.py +1 -1
- reflex/components/suneditor/editor.pyi +54 -76
- reflex/components/tags/cond_tag.py +6 -4
- reflex/components/tags/iter_tag.py +37 -25
- reflex/components/tags/match_tag.py +6 -4
- reflex/components/tags/tag.py +43 -28
- reflex/constants/base.py +3 -1
- reflex/constants/event.py +1 -0
- reflex/custom_components/custom_components.py +3 -1
- reflex/event.py +166 -108
- reflex/experimental/__init__.py +25 -6
- reflex/experimental/client_state.py +34 -57
- reflex/experimental/hooks.py +12 -17
- reflex/experimental/layout.py +4 -4
- reflex/experimental/layout.pyi +130 -180
- reflex/middleware/hydrate_middleware.py +2 -0
- reflex/middleware/middleware.py +3 -3
- reflex/model.py +22 -0
- reflex/reflex.py +4 -0
- reflex/state.py +491 -110
- reflex/style.py +56 -39
- reflex/testing.py +8 -3
- reflex/utils/exceptions.py +32 -0
- reflex/utils/exec.py +0 -14
- reflex/utils/format.py +80 -209
- reflex/utils/imports.py +16 -73
- reflex/utils/net.py +43 -0
- reflex/utils/path_ops.py +13 -1
- reflex/utils/prerequisites.py +81 -41
- reflex/utils/pyi_generator.py +12 -6
- reflex/utils/serializers.py +13 -41
- reflex/utils/telemetry.py +3 -2
- reflex/utils/types.py +47 -7
- reflex/{experimental/vars → vars}/__init__.py +6 -3
- reflex/vars/base.py +2563 -0
- reflex/vars/function.py +196 -0
- reflex/vars/number.py +1158 -0
- reflex/vars/object.py +562 -0
- reflex/vars/sequence.py +1604 -0
- {reflex-0.5.10a2.dist-info → reflex-0.6.0.dist-info}/METADATA +6 -9
- reflex-0.6.0.dist-info/RECORD +382 -0
- reflex/.templates/apps/demo/.gitignore +0 -4
- reflex/.templates/apps/demo/assets/favicon.ico +0 -0
- reflex/.templates/apps/demo/assets/github.svg +0 -10
- reflex/.templates/apps/demo/assets/icon.svg +0 -37
- reflex/.templates/apps/demo/assets/logo.svg +0 -68
- reflex/.templates/apps/demo/assets/paneleft.svg +0 -13
- reflex/.templates/apps/demo/code/__init__.py +0 -1
- reflex/.templates/apps/demo/code/demo.py +0 -127
- reflex/.templates/apps/demo/code/pages/__init__.py +0 -7
- reflex/.templates/apps/demo/code/pages/chatapp.py +0 -31
- reflex/.templates/apps/demo/code/pages/datatable.py +0 -360
- reflex/.templates/apps/demo/code/pages/forms.py +0 -257
- reflex/.templates/apps/demo/code/pages/graphing.py +0 -253
- reflex/.templates/apps/demo/code/pages/home.py +0 -56
- reflex/.templates/apps/demo/code/sidebar.py +0 -178
- reflex/.templates/apps/demo/code/state.py +0 -22
- reflex/.templates/apps/demo/code/states/form_state.py +0 -40
- reflex/.templates/apps/demo/code/states/pie_state.py +0 -47
- reflex/.templates/apps/demo/code/styles.py +0 -68
- reflex/.templates/apps/demo/code/webui/__init__.py +0 -0
- reflex/.templates/apps/demo/code/webui/components/__init__.py +0 -4
- reflex/.templates/apps/demo/code/webui/components/chat.py +0 -118
- reflex/.templates/apps/demo/code/webui/components/loading_icon.py +0 -19
- reflex/.templates/apps/demo/code/webui/components/modal.py +0 -56
- reflex/.templates/apps/demo/code/webui/components/navbar.py +0 -70
- reflex/.templates/apps/demo/code/webui/components/sidebar.py +0 -66
- reflex/.templates/apps/demo/code/webui/state.py +0 -146
- reflex/.templates/apps/demo/code/webui/styles.py +0 -88
- reflex/.templates/web/components/reflex/chakra_color_mode_provider.js +0 -36
- reflex/experimental/vars/base.py +0 -583
- reflex/experimental/vars/function.py +0 -290
- reflex/experimental/vars/number.py +0 -1458
- reflex/experimental/vars/object.py +0 -804
- reflex/experimental/vars/sequence.py +0 -1764
- reflex/utils/watch.py +0 -96
- reflex/vars.py +0 -2604
- reflex/vars.pyi +0 -218
- reflex-0.5.10a2.dist-info/RECORD +0 -413
- {reflex-0.5.10a2.dist-info → reflex-0.6.0.dist-info}/LICENSE +0 -0
- {reflex-0.5.10a2.dist-info → reflex-0.6.0.dist-info}/WHEEL +0 -0
- {reflex-0.5.10a2.dist-info → reflex-0.6.0.dist-info}/entry_points.txt +0 -0
reflex/utils/format.py
CHANGED
|
@@ -10,7 +10,7 @@ from typing import TYPE_CHECKING, Any, Callable, List, Optional, Union
|
|
|
10
10
|
|
|
11
11
|
from reflex import constants
|
|
12
12
|
from reflex.utils import exceptions, types
|
|
13
|
-
from reflex.
|
|
13
|
+
from reflex.utils.console import deprecate
|
|
14
14
|
|
|
15
15
|
if TYPE_CHECKING:
|
|
16
16
|
from reflex.components.component import ComponentStyle
|
|
@@ -263,32 +263,6 @@ def format_string(string: str) -> str:
|
|
|
263
263
|
return _wrap_js_string(_escape_js_string(string))
|
|
264
264
|
|
|
265
265
|
|
|
266
|
-
def format_f_string_prop(prop: BaseVar) -> str:
|
|
267
|
-
"""Format the string in a given prop as an f-string.
|
|
268
|
-
|
|
269
|
-
Args:
|
|
270
|
-
prop: The prop to format.
|
|
271
|
-
|
|
272
|
-
Returns:
|
|
273
|
-
The formatted string.
|
|
274
|
-
"""
|
|
275
|
-
s = prop._var_full_name
|
|
276
|
-
var_data = prop._var_data
|
|
277
|
-
interps = var_data.interpolations if var_data else []
|
|
278
|
-
parts: List[str] = []
|
|
279
|
-
|
|
280
|
-
if interps:
|
|
281
|
-
for i, (start, end) in enumerate(interps):
|
|
282
|
-
prev_end = interps[i - 1][1] if i > 0 else 0
|
|
283
|
-
parts.append(_escape_js_string(s[prev_end:start]))
|
|
284
|
-
parts.append(s[start:end])
|
|
285
|
-
parts.append(_escape_js_string(s[interps[-1][1] :]))
|
|
286
|
-
else:
|
|
287
|
-
parts.append(_escape_js_string(s))
|
|
288
|
-
|
|
289
|
-
return _wrap_js_string("".join(parts))
|
|
290
|
-
|
|
291
|
-
|
|
292
266
|
def format_var(var: Var) -> str:
|
|
293
267
|
"""Format the given Var as a javascript value.
|
|
294
268
|
|
|
@@ -298,13 +272,7 @@ def format_var(var: Var) -> str:
|
|
|
298
272
|
Returns:
|
|
299
273
|
The formatted Var.
|
|
300
274
|
"""
|
|
301
|
-
|
|
302
|
-
return str(var)
|
|
303
|
-
if types._issubclass(var._var_type, str):
|
|
304
|
-
return format_string(var._var_full_name)
|
|
305
|
-
if is_wrapped(var._var_full_name, "{"):
|
|
306
|
-
return var._var_full_name
|
|
307
|
-
return json_dumps(var._var_full_name)
|
|
275
|
+
return str(var)
|
|
308
276
|
|
|
309
277
|
|
|
310
278
|
def format_route(route: str, format_case=True) -> str:
|
|
@@ -329,46 +297,11 @@ def format_route(route: str, format_case=True) -> str:
|
|
|
329
297
|
return route
|
|
330
298
|
|
|
331
299
|
|
|
332
|
-
def
|
|
300
|
+
def format_match(
|
|
333
301
|
cond: str | Var,
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
is_prop=False,
|
|
302
|
+
match_cases: List[List[Var]],
|
|
303
|
+
default: Var,
|
|
337
304
|
) -> str:
|
|
338
|
-
"""Format a conditional expression.
|
|
339
|
-
|
|
340
|
-
Args:
|
|
341
|
-
cond: The cond.
|
|
342
|
-
true_value: The value to return if the cond is true.
|
|
343
|
-
false_value: The value to return if the cond is false.
|
|
344
|
-
is_prop: Whether the cond is a prop
|
|
345
|
-
|
|
346
|
-
Returns:
|
|
347
|
-
The formatted conditional expression.
|
|
348
|
-
"""
|
|
349
|
-
# Use Python truthiness.
|
|
350
|
-
cond = f"isTrue({cond})"
|
|
351
|
-
|
|
352
|
-
def create_var(cond_part):
|
|
353
|
-
return Var.create_safe(cond_part, _var_is_string=isinstance(cond_part, str))
|
|
354
|
-
|
|
355
|
-
# Format prop conds.
|
|
356
|
-
if is_prop:
|
|
357
|
-
true_value = create_var(true_value)
|
|
358
|
-
prop1 = true_value._replace(
|
|
359
|
-
_var_is_local=True,
|
|
360
|
-
)
|
|
361
|
-
|
|
362
|
-
false_value = create_var(false_value)
|
|
363
|
-
prop2 = false_value._replace(_var_is_local=True)
|
|
364
|
-
# unwrap '{}' to avoid f-string semantics for Var
|
|
365
|
-
return f"{cond} ? {prop1._var_name_unwrapped} : {prop2._var_name_unwrapped}"
|
|
366
|
-
|
|
367
|
-
# Format component conds.
|
|
368
|
-
return wrap(f"{cond} ? {true_value} : {false_value}", "{")
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
def format_match(cond: str | Var, match_cases: List[BaseVar], default: Var) -> str:
|
|
372
305
|
"""Format a match expression whose return type is a Var.
|
|
373
306
|
|
|
374
307
|
Args:
|
|
@@ -387,17 +320,12 @@ def format_match(cond: str | Var, match_cases: List[BaseVar], default: Var) -> s
|
|
|
387
320
|
return_value = case[-1]
|
|
388
321
|
|
|
389
322
|
case_conditions = " ".join(
|
|
390
|
-
[
|
|
391
|
-
f"case JSON.stringify({condition._var_name_unwrapped}):"
|
|
392
|
-
for condition in conditions
|
|
393
|
-
]
|
|
394
|
-
)
|
|
395
|
-
case_code = (
|
|
396
|
-
f"{case_conditions} return ({return_value._var_name_unwrapped}); break;"
|
|
323
|
+
[f"case JSON.stringify({str(condition)}):" for condition in conditions]
|
|
397
324
|
)
|
|
325
|
+
case_code = f"{case_conditions} return ({str(return_value)}); break;"
|
|
398
326
|
switch_code += case_code
|
|
399
327
|
|
|
400
|
-
switch_code += f"default: return ({default
|
|
328
|
+
switch_code += f"default: return ({str(default)}); break;"
|
|
401
329
|
switch_code += "};})()"
|
|
402
330
|
|
|
403
331
|
return switch_code
|
|
@@ -421,20 +349,15 @@ def format_prop(
|
|
|
421
349
|
# import here to avoid circular import.
|
|
422
350
|
from reflex.event import EventChain
|
|
423
351
|
from reflex.utils import serializers
|
|
352
|
+
from reflex.vars import Var
|
|
424
353
|
|
|
425
354
|
try:
|
|
426
355
|
# Handle var props.
|
|
427
356
|
if isinstance(prop, Var):
|
|
428
|
-
|
|
429
|
-
return str(prop)
|
|
430
|
-
if isinstance(prop, BaseVar) and types._issubclass(prop._var_type, str):
|
|
431
|
-
if prop._var_data and prop._var_data.interpolations:
|
|
432
|
-
return format_f_string_prop(prop)
|
|
433
|
-
return format_string(prop._var_full_name)
|
|
434
|
-
prop = prop._var_full_name
|
|
357
|
+
return str(prop)
|
|
435
358
|
|
|
436
359
|
# Handle event props.
|
|
437
|
-
|
|
360
|
+
if isinstance(prop, EventChain):
|
|
438
361
|
sig = inspect.signature(prop.args_spec) # type: ignore
|
|
439
362
|
if sig.parameters:
|
|
440
363
|
arg_def = ",".join(f"_{p}" for p in sig.parameters)
|
|
@@ -483,11 +406,15 @@ def format_props(*single_props, **key_value_props) -> list[str]:
|
|
|
483
406
|
The formatted props list.
|
|
484
407
|
"""
|
|
485
408
|
# Format all the props.
|
|
409
|
+
from reflex.vars.base import LiteralVar, Var
|
|
410
|
+
|
|
486
411
|
return [
|
|
487
|
-
|
|
412
|
+
(
|
|
413
|
+
f"{name}={{{format_prop(prop if isinstance(prop, Var) else LiteralVar.create(prop))}}}"
|
|
414
|
+
)
|
|
488
415
|
for name, prop in sorted(key_value_props.items())
|
|
489
416
|
if prop is not None
|
|
490
|
-
] + [str(prop) for prop in single_props]
|
|
417
|
+
] + [(f"{str(LiteralVar.create(prop))}") for prop in single_props]
|
|
491
418
|
|
|
492
419
|
|
|
493
420
|
def get_event_handler_parts(handler: EventHandler) -> tuple[str, str]:
|
|
@@ -502,13 +429,13 @@ def get_event_handler_parts(handler: EventHandler) -> tuple[str, str]:
|
|
|
502
429
|
# Get the class that defines the event handler.
|
|
503
430
|
parts = handler.fn.__qualname__.split(".")
|
|
504
431
|
|
|
505
|
-
# If there's no enclosing class, just return the function name.
|
|
506
|
-
if len(parts) == 1:
|
|
507
|
-
return ("", parts[-1])
|
|
508
|
-
|
|
509
432
|
# Get the state full name
|
|
510
433
|
state_full_name = handler.state_full_name
|
|
511
434
|
|
|
435
|
+
# If there's no enclosing class, just return the function name.
|
|
436
|
+
if not state_full_name:
|
|
437
|
+
return ("", parts[-1])
|
|
438
|
+
|
|
512
439
|
# Get the function name
|
|
513
440
|
name = parts[-1]
|
|
514
441
|
|
|
@@ -548,14 +475,14 @@ def format_event(event_spec: EventSpec) -> str:
|
|
|
548
475
|
[
|
|
549
476
|
":".join(
|
|
550
477
|
(
|
|
551
|
-
name.
|
|
478
|
+
name._js_expr,
|
|
552
479
|
(
|
|
553
480
|
wrap(
|
|
554
|
-
json.dumps(val.
|
|
481
|
+
json.dumps(val._js_expr).strip('"').replace("`", "\\`"),
|
|
555
482
|
"`",
|
|
556
483
|
)
|
|
557
484
|
if val._var_is_string
|
|
558
|
-
else val
|
|
485
|
+
else str(val)
|
|
559
486
|
),
|
|
560
487
|
)
|
|
561
488
|
)
|
|
@@ -572,52 +499,49 @@ def format_event(event_spec: EventSpec) -> str:
|
|
|
572
499
|
return f"Event({', '.join(event_args)})"
|
|
573
500
|
|
|
574
501
|
|
|
502
|
+
if TYPE_CHECKING:
|
|
503
|
+
from reflex.vars import Var
|
|
504
|
+
|
|
505
|
+
|
|
575
506
|
def format_event_chain(
|
|
576
507
|
event_chain: EventChain | Var[EventChain],
|
|
577
508
|
event_arg: Var | None = None,
|
|
578
509
|
) -> str:
|
|
579
|
-
"""
|
|
510
|
+
"""DEPRECATED: format an event chain as a javascript invocation.
|
|
511
|
+
|
|
512
|
+
Use str(rx.Var.create(event_chain)) instead.
|
|
580
513
|
|
|
581
514
|
Args:
|
|
582
|
-
event_chain: The event chain to
|
|
583
|
-
event_arg:
|
|
515
|
+
event_chain: The event chain to format.
|
|
516
|
+
event_arg: this argument is ignored.
|
|
584
517
|
|
|
585
518
|
Returns:
|
|
586
519
|
Compiled javascript code to queue the given event chain on the frontend.
|
|
520
|
+
"""
|
|
521
|
+
deprecate(
|
|
522
|
+
feature_name="format_event_chain",
|
|
523
|
+
reason="Use str(rx.Var.create(event_chain)) instead",
|
|
524
|
+
deprecation_version="0.6.0",
|
|
525
|
+
removal_version="0.7.0",
|
|
526
|
+
)
|
|
587
527
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
"""
|
|
591
|
-
if isinstance(event_chain, Var):
|
|
592
|
-
from reflex.event import EventChain
|
|
593
|
-
|
|
594
|
-
if event_chain._var_type is not EventChain:
|
|
595
|
-
raise ValueError(f"Invalid event chain: {event_chain}")
|
|
596
|
-
return "".join(
|
|
597
|
-
[
|
|
598
|
-
"(() => {",
|
|
599
|
-
format_var(event_chain),
|
|
600
|
-
f"; preventDefault({format_var(event_arg)})" if event_arg else "",
|
|
601
|
-
"})()",
|
|
602
|
-
]
|
|
603
|
-
)
|
|
528
|
+
from reflex.vars import Var
|
|
529
|
+
from reflex.vars.function import ArgsFunctionOperation
|
|
604
530
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
f", {format_var(event_arg)}" if event_arg else "",
|
|
610
|
-
")",
|
|
611
|
-
]
|
|
612
|
-
)
|
|
531
|
+
result = Var.create(event_chain)
|
|
532
|
+
if isinstance(result, ArgsFunctionOperation):
|
|
533
|
+
result = result._return_expr
|
|
534
|
+
return str(result)
|
|
613
535
|
|
|
614
536
|
|
|
615
537
|
def format_queue_events(
|
|
616
|
-
events:
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
538
|
+
events: (
|
|
539
|
+
EventSpec
|
|
540
|
+
| EventHandler
|
|
541
|
+
| Callable
|
|
542
|
+
| List[EventSpec | EventHandler | Callable]
|
|
543
|
+
| None
|
|
544
|
+
) = None,
|
|
621
545
|
args_spec: Optional[ArgsSpec] = None,
|
|
622
546
|
) -> Var[EventChain]:
|
|
623
547
|
"""Format a list of event handler / event spec as a javascript callback.
|
|
@@ -645,11 +569,10 @@ def format_queue_events(
|
|
|
645
569
|
call_event_fn,
|
|
646
570
|
call_event_handler,
|
|
647
571
|
)
|
|
572
|
+
from reflex.vars import FunctionVar, Var
|
|
648
573
|
|
|
649
574
|
if not events:
|
|
650
|
-
return Var.
|
|
651
|
-
"() => null", _var_is_string=False, _var_is_local=False
|
|
652
|
-
).to(EventChain)
|
|
575
|
+
return Var("(() => null)").to(FunctionVar, EventChain) # type: ignore
|
|
653
576
|
|
|
654
577
|
# If no spec is provided, the function will take no arguments.
|
|
655
578
|
def _default_args_spec():
|
|
@@ -682,12 +605,10 @@ def format_queue_events(
|
|
|
682
605
|
|
|
683
606
|
# Return the final code snippet, expecting queueEvents, processEvent, and socket to be in scope.
|
|
684
607
|
# Typically this snippet will _only_ run from within an rx.call_script eval context.
|
|
685
|
-
return Var
|
|
608
|
+
return Var(
|
|
686
609
|
f"{arg_def} => {{queueEvents([{','.join(payloads)}], {constants.CompileVars.SOCKET}); "
|
|
687
610
|
f"processEvent({constants.CompileVars.SOCKET})}}",
|
|
688
|
-
|
|
689
|
-
_var_is_local=False,
|
|
690
|
-
).to(EventChain)
|
|
611
|
+
).to(FunctionVar, EventChain) # type: ignore
|
|
691
612
|
|
|
692
613
|
|
|
693
614
|
def format_query_params(router_data: dict[str, Any]) -> dict[str, str]:
|
|
@@ -774,41 +695,6 @@ def format_ref(ref: str) -> str:
|
|
|
774
695
|
return f"ref_{clean_ref}"
|
|
775
696
|
|
|
776
697
|
|
|
777
|
-
def format_array_ref(refs: str, idx: Var | None) -> str:
|
|
778
|
-
"""Format a ref accessed by array.
|
|
779
|
-
|
|
780
|
-
Args:
|
|
781
|
-
refs : The ref array to access.
|
|
782
|
-
idx : The index of the ref in the array.
|
|
783
|
-
|
|
784
|
-
Returns:
|
|
785
|
-
The formatted ref.
|
|
786
|
-
"""
|
|
787
|
-
clean_ref = re.sub(r"[^\w]+", "_", refs)
|
|
788
|
-
if idx is not None:
|
|
789
|
-
idx._var_is_local = True
|
|
790
|
-
return f"refs_{clean_ref}[{idx}]"
|
|
791
|
-
return f"refs_{clean_ref}"
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
def format_breadcrumbs(route: str) -> list[tuple[str, str]]:
|
|
795
|
-
"""Take a route and return a list of tuple for use in breadcrumb.
|
|
796
|
-
|
|
797
|
-
Args:
|
|
798
|
-
route: The route to transform.
|
|
799
|
-
|
|
800
|
-
Returns:
|
|
801
|
-
list[tuple[str, str]]: the list of tuples for the breadcrumb.
|
|
802
|
-
"""
|
|
803
|
-
route_parts = route.lstrip("/").split("/")
|
|
804
|
-
|
|
805
|
-
# create and return breadcrumbs
|
|
806
|
-
return [
|
|
807
|
-
(part, "/".join(["", *route_parts[: i + 1]]))
|
|
808
|
-
for i, part in enumerate(route_parts)
|
|
809
|
-
]
|
|
810
|
-
|
|
811
|
-
|
|
812
698
|
def format_library_name(library_fullname: str):
|
|
813
699
|
"""Format the name of a library.
|
|
814
700
|
|
|
@@ -839,42 +725,6 @@ def json_dumps(obj: Any) -> str:
|
|
|
839
725
|
return json.dumps(obj, ensure_ascii=False, default=serializers.serialize)
|
|
840
726
|
|
|
841
727
|
|
|
842
|
-
def unwrap_vars(value: str) -> str:
|
|
843
|
-
"""Unwrap var values from a JSON string.
|
|
844
|
-
|
|
845
|
-
For example, "{var}" will be unwrapped to "var".
|
|
846
|
-
|
|
847
|
-
Args:
|
|
848
|
-
value: The JSON string to unwrap.
|
|
849
|
-
|
|
850
|
-
Returns:
|
|
851
|
-
The unwrapped JSON string.
|
|
852
|
-
"""
|
|
853
|
-
|
|
854
|
-
def unescape_double_quotes_in_var(m: re.Match) -> str:
|
|
855
|
-
prefix = m.group(1) or ""
|
|
856
|
-
# Since the outer quotes are removed, the inner escaped quotes must be unescaped.
|
|
857
|
-
return prefix + re.sub('\\\\"', '"', m.group(2))
|
|
858
|
-
|
|
859
|
-
# This substitution is necessary to unwrap var values.
|
|
860
|
-
return (
|
|
861
|
-
re.sub(
|
|
862
|
-
pattern=r"""
|
|
863
|
-
(?<!\\) # must NOT start with a backslash
|
|
864
|
-
" # match opening double quote of JSON value
|
|
865
|
-
(<reflex.Var>.*?</reflex.Var>)? # Optional encoded VarData (non-greedy)
|
|
866
|
-
{(.*?)} # extract the value between curly braces (non-greedy)
|
|
867
|
-
" # match must end with an unescaped double quote
|
|
868
|
-
""",
|
|
869
|
-
repl=unescape_double_quotes_in_var,
|
|
870
|
-
string=value,
|
|
871
|
-
flags=re.VERBOSE,
|
|
872
|
-
)
|
|
873
|
-
.replace('"`', "`")
|
|
874
|
-
.replace('`"', "`")
|
|
875
|
-
)
|
|
876
|
-
|
|
877
|
-
|
|
878
728
|
def collect_form_dict_names(form_dict: dict[str, Any]) -> dict[str, Any]:
|
|
879
729
|
"""Collapse keys with consecutive suffixes into a single list value.
|
|
880
730
|
|
|
@@ -897,6 +747,23 @@ def collect_form_dict_names(form_dict: dict[str, Any]) -> dict[str, Any]:
|
|
|
897
747
|
return collapsed
|
|
898
748
|
|
|
899
749
|
|
|
750
|
+
def format_array_ref(refs: str, idx: Var | None) -> str:
|
|
751
|
+
"""Format a ref accessed by array.
|
|
752
|
+
|
|
753
|
+
Args:
|
|
754
|
+
refs : The ref array to access.
|
|
755
|
+
idx : The index of the ref in the array.
|
|
756
|
+
|
|
757
|
+
Returns:
|
|
758
|
+
The formatted ref.
|
|
759
|
+
"""
|
|
760
|
+
clean_ref = re.sub(r"[^\w]+", "_", refs)
|
|
761
|
+
if idx is not None:
|
|
762
|
+
# idx._var_is_local = True
|
|
763
|
+
return f"refs_{clean_ref}[{str(idx)}]"
|
|
764
|
+
return f"refs_{clean_ref}"
|
|
765
|
+
|
|
766
|
+
|
|
900
767
|
def format_data_editor_column(col: str | dict):
|
|
901
768
|
"""Format a given column into the proper format.
|
|
902
769
|
|
|
@@ -909,6 +776,8 @@ def format_data_editor_column(col: str | dict):
|
|
|
909
776
|
Returns:
|
|
910
777
|
The formatted column.
|
|
911
778
|
"""
|
|
779
|
+
from reflex.vars import Var
|
|
780
|
+
|
|
912
781
|
if isinstance(col, str):
|
|
913
782
|
return {"title": col, "id": col.lower(), "type": "str"}
|
|
914
783
|
|
|
@@ -921,7 +790,7 @@ def format_data_editor_column(col: str | dict):
|
|
|
921
790
|
col["overlayIcon"] = None
|
|
922
791
|
return col
|
|
923
792
|
|
|
924
|
-
if isinstance(col,
|
|
793
|
+
if isinstance(col, Var):
|
|
925
794
|
return col
|
|
926
795
|
|
|
927
796
|
raise ValueError(
|
|
@@ -938,7 +807,9 @@ def format_data_editor_cell(cell: Any):
|
|
|
938
807
|
Returns:
|
|
939
808
|
The formatted cell.
|
|
940
809
|
"""
|
|
810
|
+
from reflex.vars.base import Var
|
|
811
|
+
|
|
941
812
|
return {
|
|
942
|
-
"kind": Var
|
|
813
|
+
"kind": Var(_js_expr="GridCellKind.Text"),
|
|
943
814
|
"data": cell,
|
|
944
815
|
}
|
reflex/utils/imports.py
CHANGED
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import dataclasses
|
|
5
6
|
from collections import defaultdict
|
|
6
|
-
from typing import Dict, List, Optional, Tuple, Union
|
|
7
|
-
|
|
8
|
-
from reflex.base import Base
|
|
7
|
+
from typing import DefaultDict, Dict, List, Optional, Tuple, Union
|
|
9
8
|
|
|
10
9
|
|
|
11
10
|
def merge_imports(
|
|
@@ -19,12 +18,22 @@ def merge_imports(
|
|
|
19
18
|
Returns:
|
|
20
19
|
The merged import dicts.
|
|
21
20
|
"""
|
|
22
|
-
all_imports = defaultdict(list)
|
|
21
|
+
all_imports: DefaultDict[str, List[ImportVar]] = defaultdict(list)
|
|
23
22
|
for import_dict in imports:
|
|
24
23
|
for lib, fields in (
|
|
25
24
|
import_dict if isinstance(import_dict, tuple) else import_dict.items()
|
|
26
25
|
):
|
|
27
|
-
|
|
26
|
+
if isinstance(fields, (list, tuple, set)):
|
|
27
|
+
all_imports[lib].extend(
|
|
28
|
+
(
|
|
29
|
+
ImportVar(field) if isinstance(field, str) else field
|
|
30
|
+
for field in fields
|
|
31
|
+
)
|
|
32
|
+
)
|
|
33
|
+
else:
|
|
34
|
+
all_imports[lib].append(
|
|
35
|
+
ImportVar(fields) if isinstance(fields, str) else fields
|
|
36
|
+
)
|
|
28
37
|
return all_imports
|
|
29
38
|
|
|
30
39
|
|
|
@@ -75,7 +84,8 @@ def collapse_imports(
|
|
|
75
84
|
}
|
|
76
85
|
|
|
77
86
|
|
|
78
|
-
|
|
87
|
+
@dataclasses.dataclass(order=True, frozen=True)
|
|
88
|
+
class ImportVar:
|
|
79
89
|
"""An import var."""
|
|
80
90
|
|
|
81
91
|
# The name of the import tag.
|
|
@@ -111,73 +121,6 @@ class ImportVar(Base):
|
|
|
111
121
|
else:
|
|
112
122
|
return self.tag or ""
|
|
113
123
|
|
|
114
|
-
def __lt__(self, other: ImportVar) -> bool:
|
|
115
|
-
"""Compare two ImportVar objects.
|
|
116
|
-
|
|
117
|
-
Args:
|
|
118
|
-
other: The other ImportVar object to compare.
|
|
119
|
-
|
|
120
|
-
Returns:
|
|
121
|
-
Whether this ImportVar object is less than the other.
|
|
122
|
-
"""
|
|
123
|
-
return (
|
|
124
|
-
self.tag,
|
|
125
|
-
self.is_default,
|
|
126
|
-
self.alias,
|
|
127
|
-
self.install,
|
|
128
|
-
self.render,
|
|
129
|
-
self.transpile,
|
|
130
|
-
) < (
|
|
131
|
-
other.tag,
|
|
132
|
-
other.is_default,
|
|
133
|
-
other.alias,
|
|
134
|
-
other.install,
|
|
135
|
-
other.render,
|
|
136
|
-
other.transpile,
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
def __eq__(self, other: ImportVar) -> bool:
|
|
140
|
-
"""Check if two ImportVar objects are equal.
|
|
141
|
-
|
|
142
|
-
Args:
|
|
143
|
-
other: The other ImportVar object to compare.
|
|
144
|
-
|
|
145
|
-
Returns:
|
|
146
|
-
Whether the two ImportVar objects are equal.
|
|
147
|
-
"""
|
|
148
|
-
return (
|
|
149
|
-
self.tag,
|
|
150
|
-
self.is_default,
|
|
151
|
-
self.alias,
|
|
152
|
-
self.install,
|
|
153
|
-
self.render,
|
|
154
|
-
self.transpile,
|
|
155
|
-
) == (
|
|
156
|
-
other.tag,
|
|
157
|
-
other.is_default,
|
|
158
|
-
other.alias,
|
|
159
|
-
other.install,
|
|
160
|
-
other.render,
|
|
161
|
-
other.transpile,
|
|
162
|
-
)
|
|
163
|
-
|
|
164
|
-
def __hash__(self) -> int:
|
|
165
|
-
"""Hash the ImportVar object.
|
|
166
|
-
|
|
167
|
-
Returns:
|
|
168
|
-
The hash of the ImportVar object.
|
|
169
|
-
"""
|
|
170
|
-
return hash(
|
|
171
|
-
(
|
|
172
|
-
self.tag,
|
|
173
|
-
self.is_default,
|
|
174
|
-
self.alias,
|
|
175
|
-
self.install,
|
|
176
|
-
self.render,
|
|
177
|
-
self.transpile,
|
|
178
|
-
)
|
|
179
|
-
)
|
|
180
|
-
|
|
181
124
|
|
|
182
125
|
ImportTypes = Union[str, ImportVar, List[Union[str, ImportVar]], List[ImportVar]]
|
|
183
126
|
ImportDict = Dict[str, ImportTypes]
|
reflex/utils/net.py
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Helpers for downloading files from the network."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
import httpx
|
|
6
|
+
|
|
7
|
+
from . import console
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _httpx_verify_kwarg() -> bool:
|
|
11
|
+
"""Get the value of the HTTPX verify keyword argument.
|
|
12
|
+
|
|
13
|
+
Returns:
|
|
14
|
+
True if SSL verification is enabled, False otherwise
|
|
15
|
+
"""
|
|
16
|
+
ssl_no_verify = os.environ.get("SSL_NO_VERIFY", "").lower() in ["true", "1", "yes"]
|
|
17
|
+
return not ssl_no_verify
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def get(url: str, **kwargs) -> httpx.Response:
|
|
21
|
+
"""Make an HTTP GET request.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
url: The URL to request.
|
|
25
|
+
**kwargs: Additional keyword arguments to pass to httpx.get.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
The response object.
|
|
29
|
+
|
|
30
|
+
Raises:
|
|
31
|
+
httpx.ConnectError: If the connection cannot be established.
|
|
32
|
+
"""
|
|
33
|
+
kwargs.setdefault("verify", _httpx_verify_kwarg())
|
|
34
|
+
try:
|
|
35
|
+
return httpx.get(url, **kwargs)
|
|
36
|
+
except httpx.ConnectError as err:
|
|
37
|
+
if "CERTIFICATE_VERIFY_FAILED" in str(err):
|
|
38
|
+
# If the error is a certificate verification error, recommend mitigating steps.
|
|
39
|
+
console.error(
|
|
40
|
+
f"Certificate verification failed for {url}. Set environment variable SSL_CERT_FILE to the "
|
|
41
|
+
"path of the certificate file or SSL_NO_VERIFY=1 to disable verification."
|
|
42
|
+
)
|
|
43
|
+
raise
|
reflex/utils/path_ops.py
CHANGED
|
@@ -81,6 +81,18 @@ def mkdir(path: str | Path):
|
|
|
81
81
|
Path(path).mkdir(parents=True, exist_ok=True)
|
|
82
82
|
|
|
83
83
|
|
|
84
|
+
def ls(path: str | Path) -> list[Path]:
|
|
85
|
+
"""List the contents of a directory.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
path: The path to the directory.
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
A list of paths to the contents of the directory.
|
|
92
|
+
"""
|
|
93
|
+
return list(Path(path).iterdir())
|
|
94
|
+
|
|
95
|
+
|
|
84
96
|
def ln(src: str | Path, dest: str | Path, overwrite: bool = False) -> bool:
|
|
85
97
|
"""Create a symbolic link.
|
|
86
98
|
|
|
@@ -197,4 +209,4 @@ def find_replace(directory: str | Path, find: str, replace: str):
|
|
|
197
209
|
filepath = Path(root, file)
|
|
198
210
|
text = filepath.read_text(encoding="utf-8")
|
|
199
211
|
text = re.sub(find, replace, text)
|
|
200
|
-
filepath.write_text(text)
|
|
212
|
+
filepath.write_text(text, encoding="utf-8")
|