reflex 0.8.9a2__py3-none-any.whl → 0.8.10__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/web/components/reflex/radix_themes_color_mode_provider.js +11 -1
- reflex/.templates/web/utils/helpers/upload.js +170 -0
- reflex/.templates/web/utils/state.js +10 -159
- reflex/app.py +9 -0
- reflex/compiler/compiler.py +3 -5
- reflex/compiler/templates.py +1 -6
- reflex/compiler/utils.py +16 -2
- reflex/components/base/bare.py +2 -2
- reflex/components/component.py +23 -23
- reflex/components/core/debounce.py +1 -1
- reflex/components/core/foreach.py +7 -19
- reflex/components/core/upload.py +1 -1
- reflex/components/dynamic.py +1 -3
- reflex/components/el/elements/forms.py +3 -3
- reflex/components/lucide/icon.py +2 -1
- reflex/components/lucide/icon.pyi +2 -1
- reflex/environment.py +13 -1
- reflex/event.py +30 -0
- reflex/model.py +4 -0
- reflex/vars/base.py +9 -2
- {reflex-0.8.9a2.dist-info → reflex-0.8.10.dist-info}/METADATA +4 -3
- {reflex-0.8.9a2.dist-info → reflex-0.8.10.dist-info}/RECORD +25 -24
- {reflex-0.8.9a2.dist-info → reflex-0.8.10.dist-info}/WHEEL +0 -0
- {reflex-0.8.9a2.dist-info → reflex-0.8.10.dist-info}/entry_points.txt +0 -0
- {reflex-0.8.9a2.dist-info → reflex-0.8.10.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useTheme } from "$/utils/react-theme";
|
|
2
|
-
import { createElement } from "react";
|
|
2
|
+
import { createElement, useEffect } from "react";
|
|
3
3
|
import { ColorModeContext, defaultColorMode } from "$/utils/context";
|
|
4
4
|
|
|
5
5
|
export default function RadixThemesColorModeProvider({ children }) {
|
|
@@ -20,6 +20,16 @@ export default function RadixThemesColorModeProvider({ children }) {
|
|
|
20
20
|
setTheme(mode);
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
const radixRoot = document.querySelector(
|
|
25
|
+
'.radix-themes[data-is-root-theme="true"]',
|
|
26
|
+
);
|
|
27
|
+
if (radixRoot) {
|
|
28
|
+
radixRoot.classList.remove("light", "dark");
|
|
29
|
+
radixRoot.classList.add(resolvedTheme);
|
|
30
|
+
}
|
|
31
|
+
}, [resolvedTheme]);
|
|
32
|
+
|
|
23
33
|
return createElement(
|
|
24
34
|
ColorModeContext.Provider,
|
|
25
35
|
{
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import JSON5 from "json5";
|
|
2
|
+
import env from "$/env.json";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Upload files to the server.
|
|
6
|
+
*
|
|
7
|
+
* @param state The state to apply the delta to.
|
|
8
|
+
* @param handler The handler to use.
|
|
9
|
+
* @param upload_id The upload id to use.
|
|
10
|
+
* @param on_upload_progress The function to call on upload progress.
|
|
11
|
+
* @param socket the websocket connection
|
|
12
|
+
* @param extra_headers Extra headers to send with the request.
|
|
13
|
+
* @param refs The refs object to store the abort controller in.
|
|
14
|
+
* @param getBackendURL Function to get the backend URL.
|
|
15
|
+
* @param getToken Function to get the Reflex token.
|
|
16
|
+
*
|
|
17
|
+
* @returns The response from posting to the UPLOADURL endpoint.
|
|
18
|
+
*/
|
|
19
|
+
export const uploadFiles = async (
|
|
20
|
+
handler,
|
|
21
|
+
files,
|
|
22
|
+
upload_id,
|
|
23
|
+
on_upload_progress,
|
|
24
|
+
extra_headers,
|
|
25
|
+
socket,
|
|
26
|
+
refs,
|
|
27
|
+
getBackendURL,
|
|
28
|
+
getToken,
|
|
29
|
+
) => {
|
|
30
|
+
// return if there's no file to upload
|
|
31
|
+
if (files === undefined || files.length === 0) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const upload_ref_name = `__upload_controllers_${upload_id}`;
|
|
36
|
+
|
|
37
|
+
if (refs[upload_ref_name]) {
|
|
38
|
+
console.log("Upload already in progress for ", upload_id);
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Track how many partial updates have been processed for this upload.
|
|
43
|
+
let resp_idx = 0;
|
|
44
|
+
const eventHandler = (progressEvent) => {
|
|
45
|
+
const event_callbacks = socket._callbacks.$event;
|
|
46
|
+
// Whenever called, responseText will contain the entire response so far.
|
|
47
|
+
const chunks = progressEvent.event.target.responseText.trim().split("\n");
|
|
48
|
+
// So only process _new_ chunks beyond resp_idx.
|
|
49
|
+
chunks.slice(resp_idx).map((chunk_json) => {
|
|
50
|
+
try {
|
|
51
|
+
const chunk = JSON5.parse(chunk_json);
|
|
52
|
+
event_callbacks.map((f, ix) => {
|
|
53
|
+
f(chunk)
|
|
54
|
+
.then(() => {
|
|
55
|
+
if (ix === event_callbacks.length - 1) {
|
|
56
|
+
// Mark this chunk as processed.
|
|
57
|
+
resp_idx += 1;
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
.catch((e) => {
|
|
61
|
+
if (progressEvent.progress === 1) {
|
|
62
|
+
// Chunk may be incomplete, so only report errors when full response is available.
|
|
63
|
+
console.log("Error processing chunk", chunk, e);
|
|
64
|
+
}
|
|
65
|
+
return;
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
} catch (e) {
|
|
69
|
+
if (progressEvent.progress === 1) {
|
|
70
|
+
console.log("Error parsing chunk", chunk_json, e);
|
|
71
|
+
}
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const controller = new AbortController();
|
|
78
|
+
const formdata = new FormData();
|
|
79
|
+
|
|
80
|
+
// Add the token and handler to the file name.
|
|
81
|
+
files.forEach((file) => {
|
|
82
|
+
formdata.append("files", file, file.path || file.name);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Send the file to the server.
|
|
86
|
+
refs[upload_ref_name] = controller;
|
|
87
|
+
|
|
88
|
+
return new Promise((resolve, reject) => {
|
|
89
|
+
const xhr = new XMLHttpRequest();
|
|
90
|
+
|
|
91
|
+
// Set up event handlers
|
|
92
|
+
xhr.onload = function () {
|
|
93
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
94
|
+
resolve({
|
|
95
|
+
data: xhr.responseText,
|
|
96
|
+
status: xhr.status,
|
|
97
|
+
statusText: xhr.statusText,
|
|
98
|
+
headers: {
|
|
99
|
+
get: (name) => xhr.getResponseHeader(name),
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
} else {
|
|
103
|
+
reject(new Error(`HTTP error! status: ${xhr.status}`));
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
xhr.onerror = function () {
|
|
108
|
+
reject(new Error("Network error"));
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
xhr.onabort = function () {
|
|
112
|
+
reject(new Error("Upload aborted"));
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// Handle upload progress
|
|
116
|
+
if (on_upload_progress) {
|
|
117
|
+
xhr.upload.onprogress = function (event) {
|
|
118
|
+
if (event.lengthComputable) {
|
|
119
|
+
const progressEvent = {
|
|
120
|
+
loaded: event.loaded,
|
|
121
|
+
total: event.total,
|
|
122
|
+
progress: event.loaded / event.total,
|
|
123
|
+
};
|
|
124
|
+
on_upload_progress(progressEvent);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Handle download progress with streaming response parsing
|
|
130
|
+
xhr.onprogress = function (event) {
|
|
131
|
+
if (eventHandler) {
|
|
132
|
+
const progressEvent = {
|
|
133
|
+
event: {
|
|
134
|
+
target: {
|
|
135
|
+
responseText: xhr.responseText,
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
progress: event.lengthComputable ? event.loaded / event.total : 0,
|
|
139
|
+
};
|
|
140
|
+
eventHandler(progressEvent);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// Handle abort controller
|
|
145
|
+
controller.signal.addEventListener("abort", () => {
|
|
146
|
+
xhr.abort();
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Configure and send request
|
|
150
|
+
xhr.open("POST", getBackendURL(env.UPLOAD));
|
|
151
|
+
xhr.setRequestHeader("Reflex-Client-Token", getToken());
|
|
152
|
+
xhr.setRequestHeader("Reflex-Event-Handler", handler);
|
|
153
|
+
for (const [key, value] of Object.entries(extra_headers || {})) {
|
|
154
|
+
xhr.setRequestHeader(key, value);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
xhr.send(formdata);
|
|
159
|
+
} catch (error) {
|
|
160
|
+
reject(error);
|
|
161
|
+
}
|
|
162
|
+
})
|
|
163
|
+
.catch((error) => {
|
|
164
|
+
console.log("Upload error:", error.message);
|
|
165
|
+
return false;
|
|
166
|
+
})
|
|
167
|
+
.finally(() => {
|
|
168
|
+
delete refs[upload_ref_name];
|
|
169
|
+
});
|
|
170
|
+
};
|
|
@@ -20,10 +20,10 @@ import {
|
|
|
20
20
|
} from "$/utils/context";
|
|
21
21
|
import debounce from "$/utils/helpers/debounce";
|
|
22
22
|
import throttle from "$/utils/helpers/throttle";
|
|
23
|
+
import { uploadFiles } from "$/utils/helpers/upload";
|
|
23
24
|
|
|
24
25
|
// Endpoint URLs.
|
|
25
26
|
const EVENTURL = env.EVENT;
|
|
26
|
-
const UPLOADURL = env.UPLOAD;
|
|
27
27
|
|
|
28
28
|
// These hostnames indicate that the backend and frontend are reachable via the same domain.
|
|
29
29
|
const SAME_DOMAIN_HOSTNAMES = ["localhost", "0.0.0.0", "::", "0:0:0:0:0:0:0:0"];
|
|
@@ -210,7 +210,11 @@ export const applyEvent = async (event, socket, navigate, params) => {
|
|
|
210
210
|
return false;
|
|
211
211
|
}
|
|
212
212
|
if (event.payload.external) {
|
|
213
|
-
window.open(
|
|
213
|
+
window.open(
|
|
214
|
+
event.payload.path,
|
|
215
|
+
"_blank",
|
|
216
|
+
"noopener" + (event.payload.popup ? ",popup" : ""),
|
|
217
|
+
);
|
|
214
218
|
return false;
|
|
215
219
|
}
|
|
216
220
|
const url = urlFrom(event.payload.path);
|
|
@@ -428,7 +432,11 @@ export const applyRestEvent = async (event, socket, navigate, params) => {
|
|
|
428
432
|
event.payload.files,
|
|
429
433
|
event.payload.upload_id,
|
|
430
434
|
event.payload.on_upload_progress,
|
|
435
|
+
event.payload.extra_headers,
|
|
431
436
|
socket,
|
|
437
|
+
refs,
|
|
438
|
+
getBackendURL,
|
|
439
|
+
getToken,
|
|
432
440
|
);
|
|
433
441
|
return false;
|
|
434
442
|
}
|
|
@@ -610,163 +618,6 @@ export const connect = async (
|
|
|
610
618
|
document.addEventListener("visibilitychange", checkVisibility);
|
|
611
619
|
};
|
|
612
620
|
|
|
613
|
-
/**
|
|
614
|
-
* Upload files to the server.
|
|
615
|
-
*
|
|
616
|
-
* @param state The state to apply the delta to.
|
|
617
|
-
* @param handler The handler to use.
|
|
618
|
-
* @param upload_id The upload id to use.
|
|
619
|
-
* @param on_upload_progress The function to call on upload progress.
|
|
620
|
-
* @param socket the websocket connection
|
|
621
|
-
*
|
|
622
|
-
* @returns The response from posting to the UPLOADURL endpoint.
|
|
623
|
-
*/
|
|
624
|
-
export const uploadFiles = async (
|
|
625
|
-
handler,
|
|
626
|
-
files,
|
|
627
|
-
upload_id,
|
|
628
|
-
on_upload_progress,
|
|
629
|
-
socket,
|
|
630
|
-
) => {
|
|
631
|
-
// return if there's no file to upload
|
|
632
|
-
if (files === undefined || files.length === 0) {
|
|
633
|
-
return false;
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
const upload_ref_name = `__upload_controllers_${upload_id}`;
|
|
637
|
-
|
|
638
|
-
if (refs[upload_ref_name]) {
|
|
639
|
-
console.log("Upload already in progress for ", upload_id);
|
|
640
|
-
return false;
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
// Track how many partial updates have been processed for this upload.
|
|
644
|
-
let resp_idx = 0;
|
|
645
|
-
const eventHandler = (progressEvent) => {
|
|
646
|
-
const event_callbacks = socket._callbacks.$event;
|
|
647
|
-
// Whenever called, responseText will contain the entire response so far.
|
|
648
|
-
const chunks = progressEvent.event.target.responseText.trim().split("\n");
|
|
649
|
-
// So only process _new_ chunks beyond resp_idx.
|
|
650
|
-
chunks.slice(resp_idx).map((chunk_json) => {
|
|
651
|
-
try {
|
|
652
|
-
const chunk = JSON5.parse(chunk_json);
|
|
653
|
-
event_callbacks.map((f, ix) => {
|
|
654
|
-
f(chunk)
|
|
655
|
-
.then(() => {
|
|
656
|
-
if (ix === event_callbacks.length - 1) {
|
|
657
|
-
// Mark this chunk as processed.
|
|
658
|
-
resp_idx += 1;
|
|
659
|
-
}
|
|
660
|
-
})
|
|
661
|
-
.catch((e) => {
|
|
662
|
-
if (progressEvent.progress === 1) {
|
|
663
|
-
// Chunk may be incomplete, so only report errors when full response is available.
|
|
664
|
-
console.log("Error processing chunk", chunk, e);
|
|
665
|
-
}
|
|
666
|
-
return;
|
|
667
|
-
});
|
|
668
|
-
});
|
|
669
|
-
} catch (e) {
|
|
670
|
-
if (progressEvent.progress === 1) {
|
|
671
|
-
console.log("Error parsing chunk", chunk_json, e);
|
|
672
|
-
}
|
|
673
|
-
return;
|
|
674
|
-
}
|
|
675
|
-
});
|
|
676
|
-
};
|
|
677
|
-
|
|
678
|
-
const controller = new AbortController();
|
|
679
|
-
const formdata = new FormData();
|
|
680
|
-
|
|
681
|
-
// Add the token and handler to the file name.
|
|
682
|
-
files.forEach((file) => {
|
|
683
|
-
formdata.append("files", file, file.path || file.name);
|
|
684
|
-
});
|
|
685
|
-
|
|
686
|
-
// Send the file to the server.
|
|
687
|
-
refs[upload_ref_name] = controller;
|
|
688
|
-
|
|
689
|
-
return new Promise((resolve, reject) => {
|
|
690
|
-
const xhr = new XMLHttpRequest();
|
|
691
|
-
|
|
692
|
-
// Set up event handlers
|
|
693
|
-
xhr.onload = function () {
|
|
694
|
-
if (xhr.status >= 200 && xhr.status < 300) {
|
|
695
|
-
resolve({
|
|
696
|
-
data: xhr.responseText,
|
|
697
|
-
status: xhr.status,
|
|
698
|
-
statusText: xhr.statusText,
|
|
699
|
-
headers: {
|
|
700
|
-
get: (name) => xhr.getResponseHeader(name),
|
|
701
|
-
},
|
|
702
|
-
});
|
|
703
|
-
} else {
|
|
704
|
-
reject(new Error(`HTTP error! status: ${xhr.status}`));
|
|
705
|
-
}
|
|
706
|
-
};
|
|
707
|
-
|
|
708
|
-
xhr.onerror = function () {
|
|
709
|
-
reject(new Error("Network error"));
|
|
710
|
-
};
|
|
711
|
-
|
|
712
|
-
xhr.onabort = function () {
|
|
713
|
-
reject(new Error("Upload aborted"));
|
|
714
|
-
};
|
|
715
|
-
|
|
716
|
-
// Handle upload progress
|
|
717
|
-
if (on_upload_progress) {
|
|
718
|
-
xhr.upload.onprogress = function (event) {
|
|
719
|
-
if (event.lengthComputable) {
|
|
720
|
-
const progressEvent = {
|
|
721
|
-
loaded: event.loaded,
|
|
722
|
-
total: event.total,
|
|
723
|
-
progress: event.loaded / event.total,
|
|
724
|
-
};
|
|
725
|
-
on_upload_progress(progressEvent);
|
|
726
|
-
}
|
|
727
|
-
};
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
// Handle download progress with streaming response parsing
|
|
731
|
-
xhr.onprogress = function (event) {
|
|
732
|
-
if (eventHandler) {
|
|
733
|
-
const progressEvent = {
|
|
734
|
-
event: {
|
|
735
|
-
target: {
|
|
736
|
-
responseText: xhr.responseText,
|
|
737
|
-
},
|
|
738
|
-
},
|
|
739
|
-
progress: event.lengthComputable ? event.loaded / event.total : 0,
|
|
740
|
-
};
|
|
741
|
-
eventHandler(progressEvent);
|
|
742
|
-
}
|
|
743
|
-
};
|
|
744
|
-
|
|
745
|
-
// Handle abort controller
|
|
746
|
-
controller.signal.addEventListener("abort", () => {
|
|
747
|
-
xhr.abort();
|
|
748
|
-
});
|
|
749
|
-
|
|
750
|
-
// Configure and send request
|
|
751
|
-
xhr.open("POST", getBackendURL(UPLOADURL));
|
|
752
|
-
xhr.setRequestHeader("Reflex-Client-Token", getToken());
|
|
753
|
-
xhr.setRequestHeader("Reflex-Event-Handler", handler);
|
|
754
|
-
|
|
755
|
-
try {
|
|
756
|
-
xhr.send(formdata);
|
|
757
|
-
} catch (error) {
|
|
758
|
-
reject(error);
|
|
759
|
-
}
|
|
760
|
-
})
|
|
761
|
-
.catch((error) => {
|
|
762
|
-
console.log("Upload error:", error.message);
|
|
763
|
-
return false;
|
|
764
|
-
})
|
|
765
|
-
.finally(() => {
|
|
766
|
-
delete refs[upload_ref_name];
|
|
767
|
-
});
|
|
768
|
-
};
|
|
769
|
-
|
|
770
621
|
/**
|
|
771
622
|
* Create an event object.
|
|
772
623
|
* @param {string} name The name of the event.
|
reflex/app.py
CHANGED
|
@@ -258,6 +258,15 @@ class UploadFile(StarletteUploadFile):
|
|
|
258
258
|
|
|
259
259
|
headers: Headers = dataclasses.field(default_factory=Headers)
|
|
260
260
|
|
|
261
|
+
@property
|
|
262
|
+
def filename(self) -> str | None:
|
|
263
|
+
"""Get the name of the uploaded file.
|
|
264
|
+
|
|
265
|
+
Returns:
|
|
266
|
+
The name of the uploaded file.
|
|
267
|
+
"""
|
|
268
|
+
return self.name
|
|
269
|
+
|
|
261
270
|
@property
|
|
262
271
|
def name(self) -> str | None:
|
|
263
272
|
"""Get the name of the uploaded file.
|
reflex/compiler/compiler.py
CHANGED
|
@@ -161,7 +161,7 @@ def _compile_page(component: BaseComponent) -> str:
|
|
|
161
161
|
# Compile the code to render the component.
|
|
162
162
|
return templates.page_template(
|
|
163
163
|
imports=imports,
|
|
164
|
-
dynamic_imports=component._get_all_dynamic_imports(),
|
|
164
|
+
dynamic_imports=sorted(component._get_all_dynamic_imports()),
|
|
165
165
|
custom_codes=component._get_all_custom_code(),
|
|
166
166
|
hooks=component._get_all_hooks(),
|
|
167
167
|
render=component.render(),
|
|
@@ -379,7 +379,7 @@ def _compile_components(
|
|
|
379
379
|
templates.custom_component_template(
|
|
380
380
|
imports=utils.compile_imports(imports),
|
|
381
381
|
components=component_renders,
|
|
382
|
-
dynamic_imports=dynamic_imports,
|
|
382
|
+
dynamic_imports=sorted(dynamic_imports),
|
|
383
383
|
custom_codes=custom_codes,
|
|
384
384
|
),
|
|
385
385
|
imports,
|
|
@@ -435,9 +435,7 @@ def _compile_stateful_components(
|
|
|
435
435
|
rendered_components.update(dict.fromkeys(dynamic_imports))
|
|
436
436
|
|
|
437
437
|
# Include custom code in the shared component.
|
|
438
|
-
rendered_components.update(
|
|
439
|
-
dict.fromkeys(component._get_all_custom_code(export=True)),
|
|
440
|
-
)
|
|
438
|
+
rendered_components.update(component._get_all_custom_code(export=True))
|
|
441
439
|
|
|
442
440
|
# Include all imports in the shared component.
|
|
443
441
|
all_import_dicts.append(component._get_all_imports())
|
reflex/compiler/templates.py
CHANGED
|
@@ -164,7 +164,7 @@ export function Layout({{children}}) {{
|
|
|
164
164
|
def app_root_template(
|
|
165
165
|
*,
|
|
166
166
|
imports: list[_ImportDict],
|
|
167
|
-
custom_codes:
|
|
167
|
+
custom_codes: Iterable[str],
|
|
168
168
|
hooks: dict[str, VarData | None],
|
|
169
169
|
window_libraries: list[tuple[str, str]],
|
|
170
170
|
render: dict[str, Any],
|
|
@@ -200,7 +200,6 @@ def app_root_template(
|
|
|
200
200
|
)
|
|
201
201
|
|
|
202
202
|
return f"""
|
|
203
|
-
import reflexGlobalStyles from '$/styles/__reflex_global_styles.css?url';
|
|
204
203
|
{imports_str}
|
|
205
204
|
{dynamic_imports_str}
|
|
206
205
|
import {{ EventLoopProvider, StateProvider, defaultColorMode }} from "$/utils/context";
|
|
@@ -211,10 +210,6 @@ import {{ Outlet }} from 'react-router';
|
|
|
211
210
|
|
|
212
211
|
{custom_code_str}
|
|
213
212
|
|
|
214
|
-
export const links = () => [
|
|
215
|
-
{{ rel: 'stylesheet', href: reflexGlobalStyles, type: 'text/css' }}
|
|
216
|
-
];
|
|
217
|
-
|
|
218
213
|
function AppWrap({{children}}) {{
|
|
219
214
|
{_render_hooks(hooks)}
|
|
220
215
|
return ({_RenderUtils.render(render)})
|
reflex/compiler/utils.py
CHANGED
|
@@ -16,7 +16,7 @@ from reflex.components.base import Description, Image, Scripts
|
|
|
16
16
|
from reflex.components.base.document import Links, ScrollRestoration
|
|
17
17
|
from reflex.components.base.document import Meta as ReactMeta
|
|
18
18
|
from reflex.components.component import Component, ComponentStyle, CustomComponent
|
|
19
|
-
from reflex.components.el.elements.metadata import Head, Meta, Title
|
|
19
|
+
from reflex.components.el.elements.metadata import Head, Link, Meta, Title
|
|
20
20
|
from reflex.components.el.elements.other import Html
|
|
21
21
|
from reflex.components.el.elements.sectioning import Body
|
|
22
22
|
from reflex.constants.state import FIELD_MARKER
|
|
@@ -26,7 +26,7 @@ from reflex.style import Style
|
|
|
26
26
|
from reflex.utils import format, imports, path_ops
|
|
27
27
|
from reflex.utils.imports import ImportVar, ParsedImportDict
|
|
28
28
|
from reflex.utils.prerequisites import get_web_dir
|
|
29
|
-
from reflex.vars.base import Field, Var
|
|
29
|
+
from reflex.vars.base import Field, Var, VarData
|
|
30
30
|
|
|
31
31
|
# To re-export this function.
|
|
32
32
|
merge_imports = imports.merge_imports
|
|
@@ -382,6 +382,20 @@ def create_document_root(
|
|
|
382
382
|
# Always include the framework meta and link tags.
|
|
383
383
|
always_head_components = [
|
|
384
384
|
ReactMeta.create(),
|
|
385
|
+
Link.create(
|
|
386
|
+
rel="stylesheet",
|
|
387
|
+
type="text/css",
|
|
388
|
+
href=Var(
|
|
389
|
+
"reflexGlobalStyles",
|
|
390
|
+
_var_data=VarData(
|
|
391
|
+
imports={
|
|
392
|
+
"$/styles/__reflex_global_styles.css?url": [
|
|
393
|
+
ImportVar(tag="reflexGlobalStyles", is_default=True)
|
|
394
|
+
]
|
|
395
|
+
}
|
|
396
|
+
),
|
|
397
|
+
),
|
|
398
|
+
),
|
|
385
399
|
Links.create(),
|
|
386
400
|
]
|
|
387
401
|
maybe_head_components = []
|
reflex/components/base/bare.py
CHANGED
|
@@ -129,7 +129,7 @@ class Bare(Component):
|
|
|
129
129
|
dynamic_imports |= component._get_all_dynamic_imports()
|
|
130
130
|
return dynamic_imports
|
|
131
131
|
|
|
132
|
-
def _get_all_custom_code(self) ->
|
|
132
|
+
def _get_all_custom_code(self) -> dict[str, None]:
|
|
133
133
|
"""Get custom code for the component.
|
|
134
134
|
|
|
135
135
|
Returns:
|
|
@@ -166,7 +166,7 @@ class Bare(Component):
|
|
|
166
166
|
)
|
|
167
167
|
return app_wrap_components
|
|
168
168
|
|
|
169
|
-
def _get_all_refs(self) ->
|
|
169
|
+
def _get_all_refs(self) -> dict[str, None]:
|
|
170
170
|
"""Get the refs for the children of the component.
|
|
171
171
|
|
|
172
172
|
Returns:
|
reflex/components/component.py
CHANGED
|
@@ -10,7 +10,7 @@ import functools
|
|
|
10
10
|
import inspect
|
|
11
11
|
import typing
|
|
12
12
|
from abc import ABC, ABCMeta, abstractmethod
|
|
13
|
-
from collections.abc import Callable, Iterator, Mapping, Sequence
|
|
13
|
+
from collections.abc import Callable, Iterable, Iterator, Mapping, Sequence
|
|
14
14
|
from dataclasses import _MISSING_TYPE, MISSING
|
|
15
15
|
from functools import wraps
|
|
16
16
|
from hashlib import md5
|
|
@@ -374,7 +374,7 @@ class BaseComponent(metaclass=BaseComponentMeta):
|
|
|
374
374
|
"""
|
|
375
375
|
|
|
376
376
|
@abstractmethod
|
|
377
|
-
def _get_all_custom_code(self) ->
|
|
377
|
+
def _get_all_custom_code(self) -> dict[str, None]:
|
|
378
378
|
"""Get custom code for the component.
|
|
379
379
|
|
|
380
380
|
Returns:
|
|
@@ -382,7 +382,7 @@ class BaseComponent(metaclass=BaseComponentMeta):
|
|
|
382
382
|
"""
|
|
383
383
|
|
|
384
384
|
@abstractmethod
|
|
385
|
-
def _get_all_refs(self) ->
|
|
385
|
+
def _get_all_refs(self) -> dict[str, None]:
|
|
386
386
|
"""Get the refs for the children of the component.
|
|
387
387
|
|
|
388
388
|
Returns:
|
|
@@ -1003,13 +1003,13 @@ class Component(BaseComponent, ABC):
|
|
|
1003
1003
|
|
|
1004
1004
|
@classmethod
|
|
1005
1005
|
@functools.cache
|
|
1006
|
-
def get_props(cls) ->
|
|
1006
|
+
def get_props(cls) -> Iterable[str]:
|
|
1007
1007
|
"""Get the unique fields for the component.
|
|
1008
1008
|
|
|
1009
1009
|
Returns:
|
|
1010
1010
|
The unique fields.
|
|
1011
1011
|
"""
|
|
1012
|
-
return
|
|
1012
|
+
return cls.get_js_fields()
|
|
1013
1013
|
|
|
1014
1014
|
@classmethod
|
|
1015
1015
|
@functools.cache
|
|
@@ -1509,19 +1509,19 @@ class Component(BaseComponent, ABC):
|
|
|
1509
1509
|
"""
|
|
1510
1510
|
return None
|
|
1511
1511
|
|
|
1512
|
-
def _get_all_custom_code(self) ->
|
|
1512
|
+
def _get_all_custom_code(self) -> dict[str, None]:
|
|
1513
1513
|
"""Get custom code for the component and its children.
|
|
1514
1514
|
|
|
1515
1515
|
Returns:
|
|
1516
1516
|
The custom code.
|
|
1517
1517
|
"""
|
|
1518
1518
|
# Store the code in a set to avoid duplicates.
|
|
1519
|
-
code =
|
|
1519
|
+
code: dict[str, None] = {}
|
|
1520
1520
|
|
|
1521
1521
|
# Add the custom code for this component.
|
|
1522
1522
|
custom_code = self._get_custom_code()
|
|
1523
1523
|
if custom_code is not None:
|
|
1524
|
-
code
|
|
1524
|
+
code[custom_code] = None
|
|
1525
1525
|
|
|
1526
1526
|
for component in self._get_components_in_props():
|
|
1527
1527
|
code |= component._get_all_custom_code()
|
|
@@ -1529,7 +1529,7 @@ class Component(BaseComponent, ABC):
|
|
|
1529
1529
|
# Add the custom code from add_custom_code method.
|
|
1530
1530
|
for clz in self._iter_parent_classes_with_method("add_custom_code"):
|
|
1531
1531
|
for item in clz.add_custom_code(self):
|
|
1532
|
-
code
|
|
1532
|
+
code[item] = None
|
|
1533
1533
|
|
|
1534
1534
|
# Add the custom code for the children.
|
|
1535
1535
|
for child in self.children:
|
|
@@ -1814,7 +1814,7 @@ class Component(BaseComponent, ABC):
|
|
|
1814
1814
|
|
|
1815
1815
|
# Add the hook code for the children.
|
|
1816
1816
|
for child in self.children:
|
|
1817
|
-
code
|
|
1817
|
+
code.update(child._get_all_hooks_internal())
|
|
1818
1818
|
|
|
1819
1819
|
return code
|
|
1820
1820
|
|
|
@@ -1838,7 +1838,7 @@ class Component(BaseComponent, ABC):
|
|
|
1838
1838
|
|
|
1839
1839
|
# Add the hook code for the children.
|
|
1840
1840
|
for child in self.children:
|
|
1841
|
-
code
|
|
1841
|
+
code.update(child._get_all_hooks())
|
|
1842
1842
|
|
|
1843
1843
|
return code
|
|
1844
1844
|
|
|
@@ -1853,16 +1853,16 @@ class Component(BaseComponent, ABC):
|
|
|
1853
1853
|
return None
|
|
1854
1854
|
return format.format_ref(self.id)
|
|
1855
1855
|
|
|
1856
|
-
def _get_all_refs(self) ->
|
|
1856
|
+
def _get_all_refs(self) -> dict[str, None]:
|
|
1857
1857
|
"""Get the refs for the children of the component.
|
|
1858
1858
|
|
|
1859
1859
|
Returns:
|
|
1860
1860
|
The refs for the children.
|
|
1861
1861
|
"""
|
|
1862
|
-
refs =
|
|
1862
|
+
refs = {}
|
|
1863
1863
|
ref = self.get_ref()
|
|
1864
1864
|
if ref is not None:
|
|
1865
|
-
refs
|
|
1865
|
+
refs[ref] = None
|
|
1866
1866
|
for child in self.children:
|
|
1867
1867
|
refs |= child._get_all_refs()
|
|
1868
1868
|
for component in self._get_components_in_props():
|
|
@@ -1994,7 +1994,7 @@ class CustomComponent(Component):
|
|
|
1994
1994
|
)
|
|
1995
1995
|
|
|
1996
1996
|
to_camel_cased_props = {
|
|
1997
|
-
format.to_camel_case(key + MEMO_MARKER)
|
|
1997
|
+
format.to_camel_case(key + MEMO_MARKER): None
|
|
1998
1998
|
for key in props
|
|
1999
1999
|
if key not in event_types
|
|
2000
2000
|
}
|
|
@@ -2048,13 +2048,13 @@ class CustomComponent(Component):
|
|
|
2048
2048
|
return hash(self.tag)
|
|
2049
2049
|
|
|
2050
2050
|
@classmethod
|
|
2051
|
-
def get_props(cls) ->
|
|
2051
|
+
def get_props(cls) -> Iterable[str]:
|
|
2052
2052
|
"""Get the props for the component.
|
|
2053
2053
|
|
|
2054
2054
|
Returns:
|
|
2055
2055
|
The set of component props.
|
|
2056
2056
|
"""
|
|
2057
|
-
return
|
|
2057
|
+
return ()
|
|
2058
2058
|
|
|
2059
2059
|
@staticmethod
|
|
2060
2060
|
def _get_event_spec_from_args_spec(name: str, event: EventChain) -> Callable:
|
|
@@ -2656,7 +2656,7 @@ class StatefulComponent(BaseComponent):
|
|
|
2656
2656
|
return set()
|
|
2657
2657
|
return self.component._get_all_dynamic_imports()
|
|
2658
2658
|
|
|
2659
|
-
def _get_all_custom_code(self, export: bool = False) ->
|
|
2659
|
+
def _get_all_custom_code(self, export: bool = False) -> dict[str, None]:
|
|
2660
2660
|
"""Get custom code for the component.
|
|
2661
2661
|
|
|
2662
2662
|
Args:
|
|
@@ -2666,19 +2666,19 @@ class StatefulComponent(BaseComponent):
|
|
|
2666
2666
|
The custom code.
|
|
2667
2667
|
"""
|
|
2668
2668
|
if self.rendered_as_shared:
|
|
2669
|
-
return
|
|
2670
|
-
return self.component._get_all_custom_code()
|
|
2671
|
-
{self._render_stateful_code(export=export)}
|
|
2669
|
+
return {}
|
|
2670
|
+
return self.component._get_all_custom_code() | (
|
|
2671
|
+
{self._render_stateful_code(export=export): None}
|
|
2672
2672
|
)
|
|
2673
2673
|
|
|
2674
|
-
def _get_all_refs(self) ->
|
|
2674
|
+
def _get_all_refs(self) -> dict[str, None]:
|
|
2675
2675
|
"""Get the refs for the children of the component.
|
|
2676
2676
|
|
|
2677
2677
|
Returns:
|
|
2678
2678
|
The refs for the children.
|
|
2679
2679
|
"""
|
|
2680
2680
|
if self.rendered_as_shared:
|
|
2681
|
-
return
|
|
2681
|
+
return {}
|
|
2682
2682
|
return self.component._get_all_refs()
|
|
2683
2683
|
|
|
2684
2684
|
def render(self) -> dict:
|
|
@@ -132,7 +132,7 @@ class DebounceInput(Component):
|
|
|
132
132
|
component.children = child.children
|
|
133
133
|
component._rename_props = child._rename_props # pyright: ignore[reportAttributeAccessIssue]
|
|
134
134
|
outer_get_all_custom_code = component._get_all_custom_code
|
|
135
|
-
component._get_all_custom_code = lambda: outer_get_all_custom_code()
|
|
135
|
+
component._get_all_custom_code = lambda: outer_get_all_custom_code() | (
|
|
136
136
|
child._get_all_custom_code()
|
|
137
137
|
)
|
|
138
138
|
return component
|
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import functools
|
|
6
6
|
import inspect
|
|
7
7
|
from collections.abc import Callable, Iterable
|
|
8
|
+
from hashlib import md5
|
|
8
9
|
from typing import Any
|
|
9
10
|
|
|
10
11
|
from reflex.components.base.fragment import Fragment
|
|
@@ -141,25 +142,12 @@ class Foreach(Component):
|
|
|
141
142
|
else:
|
|
142
143
|
render_fn = self.render_fn
|
|
143
144
|
# Otherwise, use a deterministic index, based on the render function bytecode.
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
repr(self.render_fn)
|
|
151
|
-
if not isinstance(render_fn, functools.partial)
|
|
152
|
-
else render_fn.func.__code__
|
|
153
|
-
),
|
|
154
|
-
)
|
|
155
|
-
)
|
|
156
|
-
.to_bytes(
|
|
157
|
-
length=8,
|
|
158
|
-
byteorder="big",
|
|
159
|
-
signed=True,
|
|
160
|
-
)
|
|
161
|
-
.hex()
|
|
162
|
-
)
|
|
145
|
+
if (render_fn_code := getattr(render_fn, "__code__", None)) is not None:
|
|
146
|
+
code_hash = md5(render_fn_code.co_code).hexdigest()
|
|
147
|
+
elif isinstance(render_fn, functools.partial):
|
|
148
|
+
code_hash = md5(render_fn.func.__code__.co_code).hexdigest()
|
|
149
|
+
else:
|
|
150
|
+
code_hash = md5(repr(render_fn).encode()).hexdigest()
|
|
163
151
|
props["index_var_name"] = f"index_{code_hash}"
|
|
164
152
|
|
|
165
153
|
return IterTag(
|
reflex/components/core/upload.py
CHANGED
|
@@ -260,7 +260,7 @@ class Upload(MemoizationLeaf):
|
|
|
260
260
|
props["class_name"] = ["rx-Upload", *given_class_name]
|
|
261
261
|
|
|
262
262
|
# get only upload component props
|
|
263
|
-
supported_props = cls.get_props()
|
|
263
|
+
supported_props = set(cls.get_props()) | {"on_drop"}
|
|
264
264
|
upload_props = {
|
|
265
265
|
key: value for key, value in props.items() if key in supported_props
|
|
266
266
|
}
|
reflex/components/dynamic.py
CHANGED
|
@@ -81,9 +81,7 @@ def load_dynamic_serializer():
|
|
|
81
81
|
rendered_components.update(dict.fromkeys(dynamic_imports))
|
|
82
82
|
|
|
83
83
|
# Include custom code in the shared component.
|
|
84
|
-
rendered_components.update(
|
|
85
|
-
dict.fromkeys(component._get_all_custom_code()),
|
|
86
|
-
)
|
|
84
|
+
rendered_components.update(component._get_all_custom_code())
|
|
87
85
|
|
|
88
86
|
rendered_components[
|
|
89
87
|
templates.stateful_component_template(
|
|
@@ -770,7 +770,7 @@ class Textarea(BaseHTML):
|
|
|
770
770
|
"enter_key_submit",
|
|
771
771
|
]
|
|
772
772
|
|
|
773
|
-
def _get_all_custom_code(self) ->
|
|
773
|
+
def _get_all_custom_code(self) -> dict[str, None]:
|
|
774
774
|
"""Include the custom code for auto_height and enter_key_submit functionality.
|
|
775
775
|
|
|
776
776
|
Returns:
|
|
@@ -778,9 +778,9 @@ class Textarea(BaseHTML):
|
|
|
778
778
|
"""
|
|
779
779
|
custom_code = super()._get_all_custom_code()
|
|
780
780
|
if self.auto_height is not None:
|
|
781
|
-
custom_code
|
|
781
|
+
custom_code[AUTO_HEIGHT_JS] = None
|
|
782
782
|
if self.enter_key_submit is not None:
|
|
783
|
-
custom_code
|
|
783
|
+
custom_code[ENTER_KEY_SUBMIT_JS] = None
|
|
784
784
|
return custom_code
|
|
785
785
|
|
|
786
786
|
|
reflex/components/lucide/icon.py
CHANGED
|
@@ -6,7 +6,7 @@ from reflex.utils.imports import ImportVar
|
|
|
6
6
|
from reflex.vars.base import LiteralVar, Var
|
|
7
7
|
from reflex.vars.sequence import LiteralStringVar, StringVar
|
|
8
8
|
|
|
9
|
-
LUCIDE_LIBRARY = "lucide-react@0.
|
|
9
|
+
LUCIDE_LIBRARY = "lucide-react@0.542.0"
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class LucideIconComponent(Component):
|
|
@@ -1002,6 +1002,7 @@ LUCIDE_ICON_LIST = [
|
|
|
1002
1002
|
"linkedin",
|
|
1003
1003
|
"list_check",
|
|
1004
1004
|
"list_checks",
|
|
1005
|
+
"list_chevrons_down_up",
|
|
1005
1006
|
"list_collapse",
|
|
1006
1007
|
"list_end",
|
|
1007
1008
|
"list_filter_plus",
|
|
@@ -11,7 +11,7 @@ from reflex.components.core.breakpoints import Breakpoints
|
|
|
11
11
|
from reflex.event import EventType, PointerEventInfo
|
|
12
12
|
from reflex.vars.base import Var
|
|
13
13
|
|
|
14
|
-
LUCIDE_LIBRARY = "lucide-react@0.
|
|
14
|
+
LUCIDE_LIBRARY = "lucide-react@0.542.0"
|
|
15
15
|
|
|
16
16
|
class LucideIconComponent(Component):
|
|
17
17
|
@classmethod
|
|
@@ -1067,6 +1067,7 @@ LUCIDE_ICON_LIST = [
|
|
|
1067
1067
|
"linkedin",
|
|
1068
1068
|
"list_check",
|
|
1069
1069
|
"list_checks",
|
|
1070
|
+
"list_chevrons_down_up",
|
|
1070
1071
|
"list_collapse",
|
|
1071
1072
|
"list_end",
|
|
1072
1073
|
"list_filter_plus",
|
reflex/environment.py
CHANGED
|
@@ -204,7 +204,7 @@ def interpret_env_var_value(
|
|
|
204
204
|
The interpreted value.
|
|
205
205
|
|
|
206
206
|
Raises:
|
|
207
|
-
ValueError: If the
|
|
207
|
+
ValueError: If the environment variable type is invalid.
|
|
208
208
|
"""
|
|
209
209
|
field_type = value_inside_optional(field_type)
|
|
210
210
|
|
|
@@ -556,6 +556,18 @@ class EnvironmentVariables:
|
|
|
556
556
|
# Whether to check db connections before using them.
|
|
557
557
|
SQLALCHEMY_POOL_PRE_PING: EnvVar[bool] = env_var(True)
|
|
558
558
|
|
|
559
|
+
# The size of the database connection pool.
|
|
560
|
+
SQLALCHEMY_POOL_SIZE: EnvVar[int] = env_var(5)
|
|
561
|
+
|
|
562
|
+
# The maximum overflow size of the database connection pool.
|
|
563
|
+
SQLALCHEMY_MAX_OVERFLOW: EnvVar[int] = env_var(10)
|
|
564
|
+
|
|
565
|
+
# Recycle connections after this many seconds.
|
|
566
|
+
SQLALCHEMY_POOL_RECYCLE: EnvVar[int] = env_var(-1)
|
|
567
|
+
|
|
568
|
+
# The timeout for acquiring a connection from the pool.
|
|
569
|
+
SQLALCHEMY_POOL_TIMEOUT: EnvVar[int] = env_var(30)
|
|
570
|
+
|
|
559
571
|
# Whether to ignore the redis config error. Some redis servers only allow out-of-band configuration.
|
|
560
572
|
REFLEX_IGNORE_REDIS_CONFIG_ERROR: EnvVar[bool] = env_var(False)
|
|
561
573
|
|
reflex/event.py
CHANGED
|
@@ -13,6 +13,7 @@ from typing import (
|
|
|
13
13
|
Annotated,
|
|
14
14
|
Any,
|
|
15
15
|
Generic,
|
|
16
|
+
Literal,
|
|
16
17
|
NoReturn,
|
|
17
18
|
Protocol,
|
|
18
19
|
TypeVar,
|
|
@@ -845,6 +846,7 @@ class FileUpload:
|
|
|
845
846
|
|
|
846
847
|
upload_id: str | None = None
|
|
847
848
|
on_upload_progress: EventHandler | Callable | None = None
|
|
849
|
+
extra_headers: dict[str, str] | None = None
|
|
848
850
|
|
|
849
851
|
@staticmethod
|
|
850
852
|
def on_upload_progress_args_spec(_prog: Var[dict[str, int | float | bool]]):
|
|
@@ -886,6 +888,12 @@ class FileUpload:
|
|
|
886
888
|
Var(_js_expr="upload_id"),
|
|
887
889
|
LiteralVar.create(upload_id),
|
|
888
890
|
),
|
|
891
|
+
(
|
|
892
|
+
Var(_js_expr="extra_headers"),
|
|
893
|
+
LiteralVar.create(
|
|
894
|
+
self.extra_headers if self.extra_headers is not None else {}
|
|
895
|
+
),
|
|
896
|
+
),
|
|
889
897
|
]
|
|
890
898
|
if self.on_upload_progress is not None:
|
|
891
899
|
on_upload_progress = self.on_upload_progress
|
|
@@ -962,9 +970,29 @@ def server_side(name: str, sig: inspect.Signature, **kwargs) -> EventSpec:
|
|
|
962
970
|
)
|
|
963
971
|
|
|
964
972
|
|
|
973
|
+
@overload
|
|
974
|
+
def redirect(
|
|
975
|
+
path: str | Var[str],
|
|
976
|
+
*,
|
|
977
|
+
is_external: Literal[False] = False,
|
|
978
|
+
replace: bool = False,
|
|
979
|
+
) -> EventSpec: ...
|
|
980
|
+
|
|
981
|
+
|
|
982
|
+
@overload
|
|
983
|
+
def redirect(
|
|
984
|
+
path: str | Var[str],
|
|
985
|
+
*,
|
|
986
|
+
is_external: Literal[True],
|
|
987
|
+
popup: bool = False,
|
|
988
|
+
) -> EventSpec: ...
|
|
989
|
+
|
|
990
|
+
|
|
965
991
|
def redirect(
|
|
966
992
|
path: str | Var[str],
|
|
993
|
+
*,
|
|
967
994
|
is_external: bool = False,
|
|
995
|
+
popup: bool = False,
|
|
968
996
|
replace: bool = False,
|
|
969
997
|
) -> EventSpec:
|
|
970
998
|
"""Redirect to a new path.
|
|
@@ -972,6 +1000,7 @@ def redirect(
|
|
|
972
1000
|
Args:
|
|
973
1001
|
path: The path to redirect to.
|
|
974
1002
|
is_external: Whether to open in new tab or not.
|
|
1003
|
+
popup: Whether to open in a new window or not.
|
|
975
1004
|
replace: If True, the current page will not create a new history entry.
|
|
976
1005
|
|
|
977
1006
|
Returns:
|
|
@@ -982,6 +1011,7 @@ def redirect(
|
|
|
982
1011
|
get_fn_signature(redirect),
|
|
983
1012
|
path=path,
|
|
984
1013
|
external=is_external,
|
|
1014
|
+
popup=popup,
|
|
985
1015
|
replace=replace,
|
|
986
1016
|
)
|
|
987
1017
|
|
reflex/model.py
CHANGED
|
@@ -96,6 +96,10 @@ def get_engine_args(url: str | None = None) -> dict[str, Any]:
|
|
|
96
96
|
"echo": environment.SQLALCHEMY_ECHO.get(),
|
|
97
97
|
# Check connections before returning them.
|
|
98
98
|
"pool_pre_ping": environment.SQLALCHEMY_POOL_PRE_PING.get(),
|
|
99
|
+
"pool_size": environment.SQLALCHEMY_POOL_SIZE.get(),
|
|
100
|
+
"max_overflow": environment.SQLALCHEMY_MAX_OVERFLOW.get(),
|
|
101
|
+
"pool_recycle": environment.SQLALCHEMY_POOL_RECYCLE.get(),
|
|
102
|
+
"pool_timeout": environment.SQLALCHEMY_POOL_TIMEOUT.get(),
|
|
99
103
|
}
|
|
100
104
|
conf = get_config()
|
|
101
105
|
url = url or conf.db_url
|
reflex/vars/base.py
CHANGED
|
@@ -9,7 +9,6 @@ import datetime
|
|
|
9
9
|
import functools
|
|
10
10
|
import inspect
|
|
11
11
|
import json
|
|
12
|
-
import random
|
|
13
12
|
import re
|
|
14
13
|
import string
|
|
15
14
|
import uuid
|
|
@@ -50,6 +49,7 @@ from reflex.base import Base
|
|
|
50
49
|
from reflex.constants.compiler import Hooks
|
|
51
50
|
from reflex.constants.state import FIELD_MARKER
|
|
52
51
|
from reflex.utils import console, exceptions, imports, serializers, types
|
|
52
|
+
from reflex.utils.decorator import once
|
|
53
53
|
from reflex.utils.exceptions import (
|
|
54
54
|
ComputedVarSignatureError,
|
|
55
55
|
UntypedComputedVarError,
|
|
@@ -3033,13 +3033,20 @@ def get_uuid_string_var() -> Var:
|
|
|
3033
3033
|
USED_VARIABLES = set()
|
|
3034
3034
|
|
|
3035
3035
|
|
|
3036
|
+
@once
|
|
3037
|
+
def _rng():
|
|
3038
|
+
import random
|
|
3039
|
+
|
|
3040
|
+
return random.Random(42)
|
|
3041
|
+
|
|
3042
|
+
|
|
3036
3043
|
def get_unique_variable_name() -> str:
|
|
3037
3044
|
"""Get a unique variable name.
|
|
3038
3045
|
|
|
3039
3046
|
Returns:
|
|
3040
3047
|
The unique variable name.
|
|
3041
3048
|
"""
|
|
3042
|
-
name = "".join([
|
|
3049
|
+
name = "".join([_rng().choice(string.ascii_lowercase) for _ in range(8)])
|
|
3043
3050
|
if name not in USED_VARIABLES:
|
|
3044
3051
|
USED_VARIABLES.add(name)
|
|
3045
3052
|
return name
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: reflex
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.10
|
|
4
4
|
Summary: Web apps in pure Python.
|
|
5
5
|
Project-URL: homepage, https://reflex.dev
|
|
6
6
|
Project-URL: repository, https://github.com/reflex-dev/reflex
|
|
7
7
|
Project-URL: documentation, https://reflex.dev/docs/getting-started/introduction
|
|
8
|
-
Author
|
|
9
|
-
Maintainer
|
|
8
|
+
Author: Nikhil Rao, Alek Petuskey, Masen Furer, Elijah Ahianyo, Thomas Brandeho, Khaleel Al-Adhami
|
|
9
|
+
Maintainer: Masen Furer, Khaleel Al-Adhami
|
|
10
|
+
Maintainer-email: maintainers@reflex.dev
|
|
10
11
|
License: Apache-2.0
|
|
11
12
|
License-File: LICENSE
|
|
12
13
|
Keywords: framework,web
|
|
@@ -2,13 +2,13 @@ reflex/__init__.py,sha256=_1PVYjDeA6_JyfXvL6OuKjjO6AX2oMiNcAq8AEHf6xw,10161
|
|
|
2
2
|
reflex/__init__.pyi,sha256=0D46kHVUJPE_kgYL-BjraERu-MXNCPsQTZQShrijmeQ,10148
|
|
3
3
|
reflex/__main__.py,sha256=6cVrGEyT3j3tEvlEVUatpaYfbB5EF3UVY-6vc_Z7-hw,108
|
|
4
4
|
reflex/admin.py,sha256=Nbc38y-M8iaRBvh1W6DQu_D3kEhO8JFvxrog4q2cB_E,434
|
|
5
|
-
reflex/app.py,sha256=
|
|
5
|
+
reflex/app.py,sha256=3J6VYfArjPXikkv1HEHyLVAuG2tJpbJHDFVYQvvK1C0,78129
|
|
6
6
|
reflex/assets.py,sha256=l5O_mlrTprC0lF7Rc_McOe3a0OtSLnRdNl_PqCpDCBA,3431
|
|
7
7
|
reflex/base.py,sha256=Oh664QL3fZEHErhUasFqP7fE4olYf1y-9Oj6uZI2FCU,1173
|
|
8
8
|
reflex/config.py,sha256=LsHAtdH4nkSn3q_Ie-KNdOGdflLXrFICUQov29oFjVk,21229
|
|
9
|
-
reflex/environment.py,sha256=
|
|
10
|
-
reflex/event.py,sha256=
|
|
11
|
-
reflex/model.py,sha256=
|
|
9
|
+
reflex/environment.py,sha256=BRIePrhFKTZajYlyl-KhjGsqR4_hc7KxfNCoape6Jjw,23590
|
|
10
|
+
reflex/event.py,sha256=WfM9jNCFaTpHPRVKXJVjBbwx2lgJ9GwidyWd9cS-G1I,75460
|
|
11
|
+
reflex/model.py,sha256=2QhU1TJlcDeRA23pv8usLjyDaA6FhbQRYdzsjOHzvUI,19665
|
|
12
12
|
reflex/page.py,sha256=ssCbMVFuIy60vH-YhJUzN0OxzUwXFCCD3ej56dVjp3g,3525
|
|
13
13
|
reflex/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
14
|
reflex/reflex.py,sha256=qKpWvXuA55y519MWckr6oxKSf3pCQfRCrvzsyXSuAqk,22729
|
|
@@ -26,28 +26,29 @@ reflex/.templates/web/react-router.config.js,sha256=5K1FBryYdPusn1nE513GwB5_5UdP
|
|
|
26
26
|
reflex/.templates/web/vite-plugin-safari-cachebust.js,sha256=FcyppYYBxUlZtQ-D_iyVaQIT6TBVisBH7DMzWxYm-zA,5300
|
|
27
27
|
reflex/.templates/web/app/entry.client.js,sha256=2Jv-5SQWHhHmA07BP50f1ew1V-LOsX5VoLtSInnFDj8,264
|
|
28
28
|
reflex/.templates/web/app/routes.js,sha256=-16AwZFzrVSR7DBPYZbGx3lBA5hBFJ_XF2Y-6ilharo,254
|
|
29
|
-
reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js,sha256=
|
|
29
|
+
reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js,sha256=H8F1bUUuIU8VOtbaHRStQQwlqSwrCwFF-orklp3xKiE,1198
|
|
30
30
|
reflex/.templates/web/components/shiki/code.js,sha256=4Es1pxsr-lX4hTQ5mglrwwC6O_SI-z-O60k03z8VFzQ,1144
|
|
31
31
|
reflex/.templates/web/styles/__reflex_style_reset.css,sha256=qbC6JIT643YEsvSQ0D7xBmWE5vXy94JGrKNihRuEjnA,8913
|
|
32
32
|
reflex/.templates/web/utils/react-theme.js,sha256=Aa-RND3ooGCXW6Zavzitc-v0ciKlcQDTFlDtE4mPkFI,2713
|
|
33
|
-
reflex/.templates/web/utils/state.js,sha256
|
|
33
|
+
reflex/.templates/web/utils/state.js,sha256=sf8v15y5FXGeuQg1spDRe88pl3Kdv7n4_338tqu_xkY,31894
|
|
34
34
|
reflex/.templates/web/utils/helpers/dataeditor.js,sha256=pG6MgsHuStDR7-qPipzfiK32j9bKDBa-4hZ0JSUo4JM,1623
|
|
35
35
|
reflex/.templates/web/utils/helpers/debounce.js,sha256=xGhtTRtS_xIcaeqnYVvYJNseLgQVk-DW-eFiHJYO9As,528
|
|
36
36
|
reflex/.templates/web/utils/helpers/paste.js,sha256=ef30HsR83jRzzvZnl8yV79yqFP8TC_u8SlN99cCS_OM,1799
|
|
37
37
|
reflex/.templates/web/utils/helpers/range.js,sha256=Bjr7Ex1Mghpsopjfrcp__IVFw8F8AsMiP-0nE20ZZwk,1091
|
|
38
38
|
reflex/.templates/web/utils/helpers/throttle.js,sha256=qxeyaEojaTeX36FPGftzVWrzDsRQU4iqg3U9RJz9Vj4,566
|
|
39
|
+
reflex/.templates/web/utils/helpers/upload.js,sha256=YiAv-KC-LijTsEmzG_o6YxUprgSN7Pbyd__xu8HTX6s,4814
|
|
39
40
|
reflex/app_mixins/__init__.py,sha256=Oegz3-gZLP9p2OAN5ALNbsgxuNQfS6lGZgQA8cc-9mQ,137
|
|
40
41
|
reflex/app_mixins/lifespan.py,sha256=a156ZUYVo2bN1Tv-4WmWSjojo90PP_2-V12BX0q8YNw,3543
|
|
41
42
|
reflex/app_mixins/middleware.py,sha256=BKhe0jUFO1_TylEC48LUZyaeYyPmAYW-NV4H5Rw221k,2848
|
|
42
43
|
reflex/app_mixins/mixin.py,sha256=R1YncalqDrbdPZvpKVbm72ZKmQZxYAWfuFq9JknzTqQ,305
|
|
43
44
|
reflex/compiler/__init__.py,sha256=r8jqmDSFf09iV2lHlNhfc9XrTLjNxfDNwPYlxS4cmHE,27
|
|
44
|
-
reflex/compiler/compiler.py,sha256=
|
|
45
|
-
reflex/compiler/templates.py,sha256=
|
|
46
|
-
reflex/compiler/utils.py,sha256=
|
|
45
|
+
reflex/compiler/compiler.py,sha256=KmkR33gbkYXPxlwBgsCFS5Hn7Fjpj_yFLuu6L5CYmQA,29100
|
|
46
|
+
reflex/compiler/templates.py,sha256=QATHSjsmMbH40kYpArPEIfKdmnWkBIkzGIC8JgRK9nM,20407
|
|
47
|
+
reflex/compiler/utils.py,sha256=RmeUoZMHdIfnqPl-p0ToPgwd0FEFO5u0Xbb-J20UYdQ,19621
|
|
47
48
|
reflex/components/__init__.py,sha256=eWpgWFbSQDj2TpGp6StEbxU7roQgzY7ZM0XIcIc5RE8,588
|
|
48
49
|
reflex/components/__init__.pyi,sha256=7VFHtJGIjvGtD3IiPk848IPWYSCcPRT1EyPGljLhYlU,736
|
|
49
|
-
reflex/components/component.py,sha256=
|
|
50
|
-
reflex/components/dynamic.py,sha256=
|
|
50
|
+
reflex/components/component.py,sha256=ToY6NmFGcDumWylgemkb7t4nhsnlc4QWdqiBeMbuCe4,98168
|
|
51
|
+
reflex/components/dynamic.py,sha256=M3Waonox1lMCs9db_0iz4VtmBLuETpzZvvJ8m4iNAhE,7384
|
|
51
52
|
reflex/components/field.py,sha256=j5JZFzNlET3GAIW91m1L31RypXylMAxJNm0-CJbtykM,5745
|
|
52
53
|
reflex/components/literals.py,sha256=hogLnwTJxFJODIvqihg-GD9kFZVsEBDoYzaRit56Nuk,501
|
|
53
54
|
reflex/components/props.py,sha256=BH7RiRu_EI2BRkB1PyBVp6tLeFTTV4FzGEdDIXXQ9Bk,14378
|
|
@@ -55,7 +56,7 @@ reflex/components/base/__init__.py,sha256=6DzVn2oVZqmsXYq3r9AN8Q40R0NAsyRpSyVzBD
|
|
|
55
56
|
reflex/components/base/__init__.pyi,sha256=CoM0dGGkZSKLNHe6KBS4Zgc6sRpRGM5dZ_EuVmZ2qkA,883
|
|
56
57
|
reflex/components/base/app_wrap.py,sha256=5K_myvYvHPeAJbm3BdEX17tKvdNEj6SV9RYahbIQBAQ,514
|
|
57
58
|
reflex/components/base/app_wrap.pyi,sha256=opdrLSp-IGFibjM4bPLZPxLsyhc1H6nev2F9XhPfOSg,1996
|
|
58
|
-
reflex/components/base/bare.py,sha256=
|
|
59
|
+
reflex/components/base/bare.py,sha256=_k1tx7nymFCNAmhRtT89PKBjLRldQZWxW0xPAkeZfuA,8285
|
|
59
60
|
reflex/components/base/body.py,sha256=KLPOhxVsKyjPwrY9AziCOOG_c9ckOqIhI4n2i3_Q3NU,129
|
|
60
61
|
reflex/components/base/body.pyi,sha256=VG8N-0ocwgFOJR9mXfu6a5BtIY_jR7mK9lX3Y22g9GQ,8655
|
|
61
62
|
reflex/components/base/document.py,sha256=Fr7y22NbeKeiz8kWPH2q5BpFjKdq-AmY-sxZilee_H8,636
|
|
@@ -83,9 +84,9 @@ reflex/components/core/clipboard.py,sha256=lrM4KpbioSqBclhvtrgawgeg9Vq2dKsv40xP4
|
|
|
83
84
|
reflex/components/core/clipboard.pyi,sha256=Wt84ce1rd5vje-KuzAIkn_0riAD91_VtnZcRiRBsFLs,3230
|
|
84
85
|
reflex/components/core/colors.py,sha256=gkT5o5OqI_BR5fGMcCmBUpaz99XRNol9zAis46WktI4,1564
|
|
85
86
|
reflex/components/core/cond.py,sha256=zjDM7Elf0iYpA1MtnUjXvEbD5XvYbluWDTaQ96uxZSI,5531
|
|
86
|
-
reflex/components/core/debounce.py,sha256=
|
|
87
|
+
reflex/components/core/debounce.py,sha256=mLttJ1HkrHN3pJWVpV6KNeQBJBkcPQA4yNt4vWLXZU4,5019
|
|
87
88
|
reflex/components/core/debounce.pyi,sha256=-vEa4eIS2VlHwoL1jMmAey_dMGzz0h4VbDhzC6JT6vI,3105
|
|
88
|
-
reflex/components/core/foreach.py,sha256=
|
|
89
|
+
reflex/components/core/foreach.py,sha256=A33CPPBhd2IZ3-54Tv-MhMVlNoGh99IhuQ1Z-_vQj-E,6060
|
|
89
90
|
reflex/components/core/helmet.py,sha256=9Fr2Tz_J2v8r5t1xeZClL0V5-fEWTiFAXTcJ6bECvAw,220
|
|
90
91
|
reflex/components/core/helmet.pyi,sha256=dp5AOEPQYM77-_ylpsbgbsZkUqu37RblgUGw7Y0BGcI,2391
|
|
91
92
|
reflex/components/core/html.py,sha256=JKK3MsbuzxtcVXbzvW_Q4TZuF9yk3WwiC9LmQl34rzA,1303
|
|
@@ -94,7 +95,7 @@ reflex/components/core/match.py,sha256=xBB9vtWgVlotPHq6ssng8lzxwXDDQLp9k6Ew5RPPd
|
|
|
94
95
|
reflex/components/core/responsive.py,sha256=ACZdtJ4a4F8B3dm1k8h6J2_UJx0Z5LDB7XHQ2ty4wAc,1911
|
|
95
96
|
reflex/components/core/sticky.py,sha256=2B3TxrwG2Rtp_lv1VkMOIF2bqSiT7qYGbqbiZiMKxKY,3856
|
|
96
97
|
reflex/components/core/sticky.pyi,sha256=5D-yT0LYs0ewOlUlInU7KCpuz49yKK7dirysUs1C2VI,32908
|
|
97
|
-
reflex/components/core/upload.py,sha256=
|
|
98
|
+
reflex/components/core/upload.py,sha256=Zxni0-cG3B8qx2eSFV7CSZ38gHN9r8YtosowNBHceoI,13544
|
|
98
99
|
reflex/components/core/upload.pyi,sha256=UqfcPGUs8xmnKHKuvqYV7CtOXeF_D1s9ooRe49w6C3E,15757
|
|
99
100
|
reflex/components/core/window_events.py,sha256=opbuO20zVxt252kQLk49V7cltb_Um2oh7iePeGNJ538,3355
|
|
100
101
|
reflex/components/core/window_events.pyi,sha256=aTkBiAy-e9LqkQm6_apRsXXfJRdawA11cE1tQQSIy3c,3206
|
|
@@ -116,7 +117,7 @@ reflex/components/el/elements/__init__.py,sha256=_uZaPHSQSDZBqo-v_hRZECJbWBY3Srq
|
|
|
116
117
|
reflex/components/el/elements/__init__.pyi,sha256=LCaxINN6BUqHsxgpDITjOUqJnF3x5rRI8y2fj62ZT14,8680
|
|
117
118
|
reflex/components/el/elements/base.py,sha256=4jnwyCQUHvWcIfwiIWVCiIC_jbwZlkAiOgx73t7tdw8,3075
|
|
118
119
|
reflex/components/el/elements/base.pyi,sha256=RPdq_8Z1gkV-5n2qeEVQWpPCwVSTzY4eYb6iIJVU-ig,10074
|
|
119
|
-
reflex/components/el/elements/forms.py,sha256=
|
|
120
|
+
reflex/components/el/elements/forms.py,sha256=_WleBOQniadFc0lqDM_CoBbnDoLw0LfWJD6wyr3_bQw,22017
|
|
120
121
|
reflex/components/el/elements/forms.pyi,sha256=NSmo68oksZkzOoSGA5XKNVzqU0K3WIzkFN82EDLC-f8,168115
|
|
121
122
|
reflex/components/el/elements/inline.py,sha256=q3Ku_x8L9NaXrYQovCfkWwZ5AfXG0VyhGN_OT73kA0Y,4126
|
|
122
123
|
reflex/components/el/elements/inline.pyi,sha256=0pjqiHH8DmFfghbM8MK5tqgiZGSnfT-o055GINU8xrA,231760
|
|
@@ -138,8 +139,8 @@ reflex/components/gridjs/__init__.py,sha256=xJwDm1AZ70L5-t9LLqZwGUtDpijbf1KuMYDT
|
|
|
138
139
|
reflex/components/gridjs/datatable.py,sha256=7JKrRw1zkpFB0_wwoaIhrVrldsm7-dyi3PASgqLq8Hc,4224
|
|
139
140
|
reflex/components/gridjs/datatable.pyi,sha256=kFgv82vCgfdWZaUq4bZ73G8X3mkw6ecvSRkZ9G9-28E,5185
|
|
140
141
|
reflex/components/lucide/__init__.py,sha256=EggTK2MuQKQeOBLKW-mF0VaDK9zdWBImu1HO2dvHZbE,73
|
|
141
|
-
reflex/components/lucide/icon.py,sha256=
|
|
142
|
-
reflex/components/lucide/icon.pyi,sha256=
|
|
142
|
+
reflex/components/lucide/icon.py,sha256=wetRyx6HB5tAZ4ntAV5fbf3VuhkEj7zosoLStGYGjBA,35321
|
|
143
|
+
reflex/components/lucide/icon.pyi,sha256=7HEqYp0fGgNyi_nTrpCZNQSuEBnFEzJRb9pWTQKJ-dM,38115
|
|
143
144
|
reflex/components/markdown/__init__.py,sha256=Dfl1At5uYoY7H4ufZU_RY2KOGQDLtj75dsZ2BTqqAns,87
|
|
144
145
|
reflex/components/markdown/markdown.py,sha256=kzvO2VnfCbxV7AcIMBJbxLtAlQ6U5T_QB_JTh8l-HJ4,15450
|
|
145
146
|
reflex/components/markdown/markdown.pyi,sha256=oOlXZItHB0TPWsFz1Qjvr3KzG8sssthBp40UO_KkRIA,4322
|
|
@@ -372,7 +373,7 @@ reflex/utils/templates.py,sha256=tWo3jO6laQX8b0gUsqHkio_hUQGIvFbmXC-lxiGcdRo,142
|
|
|
372
373
|
reflex/utils/token_manager.py,sha256=o_HGbqT9WfYRmek2iY9nem4vDZMz8Q4Dra-eW1lKmuA,6999
|
|
373
374
|
reflex/utils/types.py,sha256=Xh9jXSMBgwrR-Whn_5qAnjqQWzHiIJbm1b8qwMG4QmY,38511
|
|
374
375
|
reflex/vars/__init__.py,sha256=85eXMt32bFoKtMdH3KxYRMD8mtnKyYiQcThPxJLoW1k,1359
|
|
375
|
-
reflex/vars/base.py,sha256=
|
|
376
|
+
reflex/vars/base.py,sha256=CJT6SVtFDcBBpOtLw6jtszgZYifqeS3UJVsZ5y-BJQQ,113350
|
|
376
377
|
reflex/vars/datetime.py,sha256=F2Jv_bfydipFSkIQ1F6x5MnSgFEyES9Vq5RG_uGH81E,5118
|
|
377
378
|
reflex/vars/dep_tracking.py,sha256=LfDGgAGlqfC0DeiVcitRBcA1uCe1C3fNRARRekLgCz4,13738
|
|
378
379
|
reflex/vars/function.py,sha256=0i-VkxHkDJmZtfQUwUfaF0rlS6WM8azjwQ8k7rEOkyk,13944
|
|
@@ -380,8 +381,8 @@ reflex/vars/number.py,sha256=tO7pnvFaBsedq1HWT4skytnSqHWMluGEhUbjAUMx8XQ,28190
|
|
|
380
381
|
reflex/vars/object.py,sha256=YblDxQYMajR19a7qjavXcM7-9A6MweAH1giw5fjPci4,17349
|
|
381
382
|
reflex/vars/sequence.py,sha256=1kBrqihspyjyQ1XDqFPC8OpVGtZs_EVkOdIKBro5ilA,55249
|
|
382
383
|
scripts/hatch_build.py,sha256=-4pxcLSFmirmujGpQX9UUxjhIC03tQ_fIQwVbHu9kc0,1861
|
|
383
|
-
reflex-0.8.
|
|
384
|
-
reflex-0.8.
|
|
385
|
-
reflex-0.8.
|
|
386
|
-
reflex-0.8.
|
|
387
|
-
reflex-0.8.
|
|
384
|
+
reflex-0.8.10.dist-info/METADATA,sha256=3ska8-7YBaAwHA5LP77s80KPxvnbPsKt_NgPr6YEoFs,12334
|
|
385
|
+
reflex-0.8.10.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
386
|
+
reflex-0.8.10.dist-info/entry_points.txt,sha256=Rxt4dXc7MLBNt5CSHTehVPuSe9Xqow4HLX55nD9tQQ0,45
|
|
387
|
+
reflex-0.8.10.dist-info/licenses/LICENSE,sha256=dw3zLrp9f5ObD7kqS32vWfhcImfO52PMmRqvtxq_YEE,11358
|
|
388
|
+
reflex-0.8.10.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|