supervisely 6.73.271__py3-none-any.whl → 6.73.273__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 supervisely might be problematic. Click here for more details.
- supervisely/app/fastapi/index.html +245 -148
- supervisely/app/fastapi/subapp.py +5 -1
- supervisely/app/fastapi/templating.py +19 -2
- supervisely/cli/release/release.py +38 -0
- supervisely/project/project.py +17 -7
- {supervisely-6.73.271.dist-info → supervisely-6.73.273.dist-info}/METADATA +1 -1
- {supervisely-6.73.271.dist-info → supervisely-6.73.273.dist-info}/RECORD +11 -11
- {supervisely-6.73.271.dist-info → supervisely-6.73.273.dist-info}/LICENSE +0 -0
- {supervisely-6.73.271.dist-info → supervisely-6.73.273.dist-info}/WHEEL +0 -0
- {supervisely-6.73.271.dist-info → supervisely-6.73.273.dist-info}/entry_points.txt +0 -0
- {supervisely-6.73.271.dist-info → supervisely-6.73.273.dist-info}/top_level.txt +0 -0
|
@@ -1,163 +1,260 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html>
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
margin: 10px 0;
|
|
23
|
-
position: relative;
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<link id="favicon" rel="icon" type="image/x-icon" href="{{{__favicon__}}}" />
|
|
6
|
+
<link type="text/css" rel="stylesheet"
|
|
7
|
+
href="https://cdn.jsdelivr.net/gh/supervisely/js-bundle@{{{js_bundle_version}}}/sly-app-widgets-{{{js_bundle_version}}}.bundle.css" />
|
|
8
|
+
<style>
|
|
9
|
+
#app-global-loading-icon {
|
|
10
|
+
background: white;
|
|
11
|
+
border-radius: 50%;
|
|
12
|
+
width: 75px;
|
|
13
|
+
height: 75px;
|
|
14
|
+
padding: 10px;
|
|
15
|
+
margin: 10px 0;
|
|
16
|
+
position: relative;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@keyframes app-loading-rotation {
|
|
20
|
+
0% {
|
|
21
|
+
transform: rotate(0deg);
|
|
24
22
|
}
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
transform: rotate(0deg);
|
|
29
|
-
}
|
|
30
|
-
100% {
|
|
31
|
-
transform: rotate(360deg);
|
|
32
|
-
}
|
|
24
|
+
100% {
|
|
25
|
+
transform: rotate(360deg);
|
|
33
26
|
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
#app-global-loading-icon::after {
|
|
30
|
+
content: "";
|
|
31
|
+
box-sizing: border-box;
|
|
32
|
+
position: absolute;
|
|
33
|
+
left: 0;
|
|
34
|
+
top: 0;
|
|
35
|
+
transform: translate(-50%, -50%);
|
|
36
|
+
width: 95px;
|
|
37
|
+
height: 95px;
|
|
38
|
+
border-radius: 50%;
|
|
39
|
+
border: 3px solid transparent;
|
|
40
|
+
border-bottom-color: #fb4481;
|
|
41
|
+
animation: app-loading-rotation 1s linear infinite;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
#app-global-loading-icon>img {
|
|
45
|
+
width: 75px;
|
|
46
|
+
border-radius: 50%;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.extended-app-header .app-session-header-widget>div {
|
|
50
|
+
margin-bottom: 0;
|
|
51
|
+
padding-left: 20px;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.app-session-header-solid {
|
|
55
|
+
background: white;
|
|
56
|
+
box-shadow: 0 5px 10px #0000000d;
|
|
57
|
+
border-bottom: 1px solid #dfe2e8;
|
|
58
|
+
position: relative;
|
|
59
|
+
}
|
|
60
|
+
</style>
|
|
61
|
+
<title>{{{app_name}}}</title>
|
|
62
|
+
</head>
|
|
63
|
+
|
|
64
|
+
<body style="background-color: #f4f7fe">
|
|
65
|
+
<center>
|
|
66
|
+
<div id="app-global-loading-icon">
|
|
67
|
+
<img src="https://app.supervise.ly/loading.gif" />
|
|
68
|
+
</div>
|
|
69
|
+
</center>
|
|
70
|
+
{% if __webpy_script__ %}
|
|
71
|
+
<script src="https://cdn.jsdelivr.net/pyodide/{{{pyodide_version}}}/full/pyodide.js"></script>
|
|
72
|
+
{% endif %}
|
|
73
|
+
<script
|
|
74
|
+
src="https://cdn.jsdelivr.net/gh/supervisely/js-bundle@{{{js_bundle_version}}}/sly-app-widgets-{{{js_bundle_version}}}.bundle.js"></script>
|
|
75
|
+
<script type="module"
|
|
76
|
+
src="https://cdn.jsdelivr.net/gh/supervisely-ecosystem/supervisely-app-frontend-js@v{{{js_frontend_version}}}/SlyApp.js"></script>
|
|
77
|
+
<script>
|
|
78
|
+
window.parent.postMessage('{ "showHeader": false }', "*");
|
|
79
|
+
</script>
|
|
80
|
+
|
|
81
|
+
{% for scripts in __widget_scripts__.values() %} {% if scripts is string %}
|
|
82
|
+
<script src="{{{ scripts }}}"></script>
|
|
83
|
+
{% else %} {% for scripts in scripts %}
|
|
84
|
+
<script src="{{{ scripts }}}"></script>
|
|
85
|
+
{% endfor %} {% endif %} {% endfor %}
|
|
86
|
+
|
|
87
|
+
<div id="sly-app">
|
|
88
|
+
<sly-app>
|
|
89
|
+
<template v-slot="{ post, state, data, session }">
|
|
90
|
+
<div
|
|
91
|
+
:style="{'padding': `${state.app_body_padding} ${state.app_body_padding} 0`, 'display': 'flex', 'flex-direction': 'row', 'place-items': 'center'}"
|
|
92
|
+
{% if __app_session_info_solid__ %} {% if __app_session_info_extra_content__ %}
|
|
93
|
+
class="app-session-header-solid extended-app-header" {% else %} class="app-session-header-solid" {% endif %}
|
|
94
|
+
{% else %} {% if __app_session_info_extra_content__ %} class="extended-app-header" {% endif %} {% endif %}>
|
|
95
|
+
<sly-app-header v-if="session" :session="session" :data="data" :state="state"></sly-app-header>
|
|
96
|
+
{% if __app_session_info_extra_content__ %}
|
|
97
|
+
{{{__app_session_info_extra_content__}}} {% endif %}
|
|
98
|
+
</div>
|
|
99
|
+
<div :style="{'padding': `0 ${state.app_body_padding} ${state.app_body_padding}`}" {% if __webpy_script__
|
|
100
|
+
%}v-loading="state.app_initializing" {% endif %}>
|
|
101
|
+
{% if __no_html_mode__ %} {% include 'no_html_main.html' %} {% else
|
|
102
|
+
%} {% include 'main.html' %} {% endif %} {% include
|
|
103
|
+
'dialog_window.html' %}
|
|
104
|
+
</div>
|
|
105
|
+
</template>
|
|
106
|
+
</sly-app>
|
|
107
|
+
</div>
|
|
34
108
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
border-radius: 50%;
|
|
45
|
-
border: 3px solid transparent;
|
|
46
|
-
border-bottom-color: #fb4481;
|
|
47
|
-
animation: app-loading-rotation 1s linear infinite;
|
|
109
|
+
<!-- Offline session styles fix -->
|
|
110
|
+
<script>
|
|
111
|
+
let resizeCounter = 0;
|
|
112
|
+
let resizeInterval = setInterval(() => {
|
|
113
|
+
resizeCounter += 1;
|
|
114
|
+
window.dispatchEvent(new Event("resize"));
|
|
115
|
+
|
|
116
|
+
if (resizeCounter > 3) {
|
|
117
|
+
clearInterval(resizeInterval);
|
|
48
118
|
}
|
|
119
|
+
}, 2000);
|
|
120
|
+
|
|
121
|
+
let pyodide = null;
|
|
122
|
+
let mainScriptTxt = null;
|
|
123
|
+
|
|
124
|
+
async function loadDependency(pyodide, url, modulePath) {
|
|
125
|
+
const pythonCode = await fetch(url).then(response => response.text());
|
|
126
|
+
const FS = pyodide.FS;
|
|
127
|
+
FS.writeFile(modulePath, pythonCode);
|
|
128
|
+
}
|
|
49
129
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
130
|
+
async function setupAndImportPythonPackage(url, packageName) {
|
|
131
|
+
const FS = pyodide.FS;
|
|
132
|
+
|
|
133
|
+
const response = await fetch(url);
|
|
134
|
+
if (!response.ok) {
|
|
135
|
+
throw new Error(`Failed to fetch TAR file: ${response.statusText}`);
|
|
53
136
|
}
|
|
137
|
+
const tarData = await response.arrayBuffer();
|
|
138
|
+
|
|
139
|
+
const tarPath = `${packageName}.tar`;
|
|
140
|
+
FS.writeFile(tarPath, new Uint8Array(tarData));
|
|
141
|
+
|
|
142
|
+
const extractTo = `./`;
|
|
143
|
+
const pythonCode = `
|
|
144
|
+
import tarfile
|
|
145
|
+
import sys
|
|
146
|
+
import os
|
|
147
|
+
|
|
148
|
+
tar_path = "${tarPath}"
|
|
149
|
+
extract_to = "${extractTo}"
|
|
150
|
+
|
|
151
|
+
os.makedirs(extract_to, exist_ok=True)
|
|
152
|
+
with tarfile.open(tar_path, "r:") as tar_ref:
|
|
153
|
+
tar_ref.extractall(extract_to)
|
|
154
|
+
`;
|
|
155
|
+
await pyodide.runPythonAsync(pythonCode);
|
|
156
|
+
|
|
157
|
+
console.log(`Package ${packageName} extracted to ${extractTo}`);
|
|
158
|
+
}
|
|
54
159
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
160
|
+
const allowedActions = new Set([
|
|
161
|
+
{% if events_subscribed %}
|
|
162
|
+
{% for event in events_subscribed %}
|
|
163
|
+
'{{{ event }}}',
|
|
164
|
+
{% endfor %}
|
|
165
|
+
{% endif %}
|
|
166
|
+
]);
|
|
167
|
+
let unSubStoreAction = null;
|
|
168
|
+
|
|
169
|
+
function subToStoreAction() {
|
|
170
|
+
if (unSubStoreAction) {
|
|
171
|
+
unSubStoreAction();
|
|
58
172
|
}
|
|
59
173
|
|
|
60
|
-
.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
174
|
+
const store = window.slyApp.store;
|
|
175
|
+
|
|
176
|
+
unSubStoreAction = store.subscribeAction((action) => {
|
|
177
|
+
if (!allowedActions.has(action.type)) return;
|
|
178
|
+
runPythonScript(action);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
console.log("Subscribed to store actions");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async function loadMainPythonScript() {
|
|
185
|
+
pyodide = await loadPyodide();
|
|
186
|
+
await pyodide.loadPackage("micropip");
|
|
187
|
+
const micropip = pyodide.pyimport("micropip");
|
|
188
|
+
await micropip.install(["typing_extensions == 4.8"]) // needed for fastapi
|
|
189
|
+
await micropip.install(["ssl"]) // needed for fastapi
|
|
190
|
+
await micropip.install(["fastapi"]) // needed for sdk
|
|
191
|
+
|
|
192
|
+
{% if pyodide_requirements %}
|
|
193
|
+
{% for req in pyodide_requirements %}
|
|
194
|
+
await micropip.install(["{{{ req | safe }}}"])
|
|
195
|
+
{% endfor %}
|
|
196
|
+
{% endif %}
|
|
197
|
+
|
|
198
|
+
await setupAndImportPythonPackage("./sly_sdk.tar", "sly_sdk") // temporary solution
|
|
199
|
+
await setupAndImportPythonPackage("./src.tar", "src")
|
|
200
|
+
{% if src_modules %}
|
|
201
|
+
{% for module in src_modules %}
|
|
202
|
+
await loadDependency(pyodide, "./{{{ module }}}", "{{{ module }}}")
|
|
203
|
+
{% endfor %}
|
|
204
|
+
{% endif %}
|
|
205
|
+
|
|
206
|
+
mainScriptTxt = await fetch("./{{{ __webpy_script__ }}}").then((response) => response.text());
|
|
207
|
+
python_code = `
|
|
208
|
+
from sly_sdk.webpy import WebPyApplication
|
|
209
|
+
app = WebPyApplication()
|
|
210
|
+
state = app.state
|
|
211
|
+
if state.get("app_initializing", False) == True:
|
|
212
|
+
state["app_initializing"] = False
|
|
213
|
+
state.send_changes()
|
|
214
|
+
`
|
|
215
|
+
const fn = pyodide.runPython(python_code);
|
|
216
|
+
if (typeof fn === "function") {
|
|
217
|
+
const newParams = params.map(p => pyodide.toPy(p));
|
|
218
|
+
result = fn(...newParams);
|
|
219
|
+
} else {
|
|
220
|
+
result = fn;
|
|
65
221
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
</head>
|
|
69
|
-
|
|
70
|
-
<body style="background-color: #f4f7fe">
|
|
71
|
-
<center>
|
|
72
|
-
<div id="app-global-loading-icon">
|
|
73
|
-
<img src="https://app.supervise.ly/loading.gif" />
|
|
74
|
-
</div>
|
|
75
|
-
</center>
|
|
76
|
-
<script src="https://cdn.jsdelivr.net/gh/supervisely/js-bundle@{{{js_bundle_version}}}/sly-app-widgets-{{{js_bundle_version}}}.bundle.js"></script>
|
|
77
|
-
<script
|
|
78
|
-
type="module"
|
|
79
|
-
src="https://cdn.jsdelivr.net/gh/supervisely-ecosystem/supervisely-app-frontend-js@v{{{js_frontend_version}}}/SlyApp.js"
|
|
80
|
-
></script>
|
|
81
|
-
<script>
|
|
82
|
-
window.parent.postMessage('{ "showHeader": false }', "*");
|
|
83
|
-
</script>
|
|
84
|
-
|
|
85
|
-
{% for scripts in __widget_scripts__.values() %} {% if scripts is string %}
|
|
86
|
-
<script src="{{{ scripts }}}"></script>
|
|
87
|
-
{% else %} {% for scripts in scripts %}
|
|
88
|
-
<script src="{{{ scripts }}}"></script>
|
|
89
|
-
{% endfor %} {% endif %} {% endfor %}
|
|
90
|
-
|
|
91
|
-
<div id="sly-app">
|
|
92
|
-
<sly-app>
|
|
93
|
-
<template v-slot="{ post, state, data, session }">
|
|
94
|
-
<div
|
|
95
|
-
:style="{'padding': `${state.app_body_padding} ${state.app_body_padding} 0`, 'display': 'flex', 'flex-direction': 'row', 'place-items': 'center'}"
|
|
96
|
-
{%
|
|
97
|
-
if
|
|
98
|
-
__app_session_info_solid__
|
|
99
|
-
%}
|
|
100
|
-
{%
|
|
101
|
-
if
|
|
102
|
-
__app_session_info_extra_content__
|
|
103
|
-
%}
|
|
104
|
-
class="app-session-header-solid extended-app-header"
|
|
105
|
-
{%
|
|
106
|
-
else
|
|
107
|
-
%}
|
|
108
|
-
class="app-session-header-solid"
|
|
109
|
-
{%
|
|
110
|
-
endif
|
|
111
|
-
%}
|
|
112
|
-
{%
|
|
113
|
-
else
|
|
114
|
-
%}
|
|
115
|
-
{%
|
|
116
|
-
if
|
|
117
|
-
__app_session_info_extra_content__
|
|
118
|
-
%}
|
|
119
|
-
class="extended-app-header"
|
|
120
|
-
{%
|
|
121
|
-
endif
|
|
122
|
-
%}
|
|
123
|
-
{%
|
|
124
|
-
endif
|
|
125
|
-
%}
|
|
126
|
-
>
|
|
127
|
-
<sly-app-header
|
|
128
|
-
v-if="session"
|
|
129
|
-
:session="session"
|
|
130
|
-
:data="data"
|
|
131
|
-
:state="state"
|
|
132
|
-
></sly-app-header>
|
|
133
|
-
{% if __app_session_info_extra_content__ %}
|
|
134
|
-
{{{__app_session_info_extra_content__}}} {% endif %}
|
|
135
|
-
</div>
|
|
136
|
-
<div
|
|
137
|
-
:style="{'padding': `0 ${state.app_body_padding} ${state.app_body_padding}`}"
|
|
138
|
-
>
|
|
139
|
-
{% if __no_html_mode__ %} {% include 'no_html_main.html' %} {% else
|
|
140
|
-
%} {% include 'main.html' %} {% endif %} {% include
|
|
141
|
-
'dialog_window.html' %}
|
|
142
|
-
</div>
|
|
143
|
-
</template>
|
|
144
|
-
</sly-app>
|
|
145
|
-
</div>
|
|
222
|
+
subToStoreAction();
|
|
223
|
+
}
|
|
146
224
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
225
|
+
let initPromise = null;
|
|
226
|
+
|
|
227
|
+
async function runPythonScript(...params) {
|
|
228
|
+
if (initPromise) {
|
|
229
|
+
await initPromise;
|
|
230
|
+
initPromise = null;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
let result;
|
|
234
|
+
const timeStart = performance.now();
|
|
235
|
+
|
|
236
|
+
const fn = pyodide.runPython(mainScriptTxt);
|
|
237
|
+
if (typeof fn === "function") {
|
|
238
|
+
const newParams = params.map(p => pyodide.toPy(p));
|
|
239
|
+
result = fn(...newParams);
|
|
240
|
+
} else {
|
|
241
|
+
result = fn;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const timeEnd = performance.now();
|
|
245
|
+
console.log("Web Python script executed in", timeEnd - timeStart, "ms");
|
|
246
|
+
|
|
247
|
+
return result;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const runPythonScriptThrottled = _.throttle(runPythonScript, 50);
|
|
251
|
+
{% if __webpy_script__ %}
|
|
252
|
+
initPromise = loadMainPythonScript();
|
|
161
253
|
{% endif %}
|
|
162
|
-
</
|
|
163
|
-
|
|
254
|
+
</script>
|
|
255
|
+
<!-- Hot reload script -->
|
|
256
|
+
{% if HOTRELOAD %} {{{ hot_reload.script(url_for('hot-reload')) | safe }}}
|
|
257
|
+
{% endif %}
|
|
258
|
+
</body>
|
|
259
|
+
|
|
260
|
+
</html>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import os
|
|
2
1
|
import inspect
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
3
4
|
import signal
|
|
4
5
|
import sys
|
|
5
6
|
from contextlib import suppress
|
|
@@ -1060,6 +1061,9 @@ class Application(metaclass=Singleton):
|
|
|
1060
1061
|
|
|
1061
1062
|
return inner
|
|
1062
1063
|
|
|
1064
|
+
def render(self, context: Dict[str, Any]):
|
|
1065
|
+
return Jinja2Templates().render("index.html", {**context, "HOTRELOAD": False})
|
|
1066
|
+
|
|
1063
1067
|
def set_ready_check_function(self, func: Callable):
|
|
1064
1068
|
self._ready_check_function = func
|
|
1065
1069
|
|
|
@@ -11,10 +11,13 @@ from supervisely.app.singleton import Singleton
|
|
|
11
11
|
from supervisely.app.widgets_context import JinjaWidgets
|
|
12
12
|
|
|
13
13
|
# https://github.com/supervisely/js-bundle
|
|
14
|
-
js_bundle_version = "2.1.
|
|
14
|
+
js_bundle_version = "2.1.97"
|
|
15
15
|
|
|
16
16
|
# https://github.com/supervisely-ecosystem/supervisely-app-frontend-js
|
|
17
|
-
js_frontend_version = "v0.0.
|
|
17
|
+
js_frontend_version = "v0.0.54"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
pyodide_version = "v0.25.0"
|
|
18
21
|
|
|
19
22
|
|
|
20
23
|
class Jinja2Templates(_fastapi_Jinja2Templates, metaclass=Singleton):
|
|
@@ -65,3 +68,17 @@ class Jinja2Templates(_fastapi_Jinja2Templates, metaclass=Singleton):
|
|
|
65
68
|
return super().TemplateResponse(
|
|
66
69
|
name, context_with_widgets, status_code, headers, media_type, background
|
|
67
70
|
)
|
|
71
|
+
|
|
72
|
+
def render(self, name: str, context: dict) -> str:
|
|
73
|
+
from supervisely.app.fastapi.subapp import get_name_from_env
|
|
74
|
+
|
|
75
|
+
context_with_widgets = {
|
|
76
|
+
**context,
|
|
77
|
+
**JinjaWidgets().context,
|
|
78
|
+
"js_bundle_version": js_bundle_version,
|
|
79
|
+
"js_frontend_version": js_frontend_version,
|
|
80
|
+
"pyodide_version": pyodide_version,
|
|
81
|
+
"app_name": get_name_from_env(default="Supervisely App"),
|
|
82
|
+
}
|
|
83
|
+
template: jinja2.Template = self.get_template(name)
|
|
84
|
+
return template.render(context_with_widgets)
|
|
@@ -6,6 +6,7 @@ import re
|
|
|
6
6
|
import shutil
|
|
7
7
|
import string
|
|
8
8
|
import subprocess
|
|
9
|
+
import sys
|
|
9
10
|
import tarfile
|
|
10
11
|
from pathlib import Path
|
|
11
12
|
|
|
@@ -15,6 +16,29 @@ from giturlparse import parse
|
|
|
15
16
|
from requests_toolbelt import MultipartEncoder, MultipartEncoderMonitor
|
|
16
17
|
from tqdm import tqdm
|
|
17
18
|
|
|
19
|
+
from supervisely.io.fs import dir_exists, list_files_recursively, remove_dir
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class cd:
|
|
23
|
+
def __init__(self, new_path=None, add_to_path=False):
|
|
24
|
+
self.new_path = new_path
|
|
25
|
+
self.add_to_path = add_to_path
|
|
26
|
+
self._should_remove_from_path = False
|
|
27
|
+
|
|
28
|
+
def __enter__(self):
|
|
29
|
+
self.old_path = os.getcwd()
|
|
30
|
+
if self.new_path is not None:
|
|
31
|
+
os.chdir(self.new_path)
|
|
32
|
+
if self.add_to_path and not self.new_path in sys.path:
|
|
33
|
+
sys.path.insert(0, self.new_path)
|
|
34
|
+
self._should_remove_from_path = True
|
|
35
|
+
return self
|
|
36
|
+
|
|
37
|
+
def __exit__(self, etype, value, traceback):
|
|
38
|
+
os.chdir(self.old_path)
|
|
39
|
+
if self._should_remove_from_path:
|
|
40
|
+
sys.path.remove(self.new_path)
|
|
41
|
+
|
|
18
42
|
|
|
19
43
|
def slug_is_valid(slug):
|
|
20
44
|
splitted = slug.split("/")
|
|
@@ -192,7 +216,18 @@ def archive_application(repo: git.Repo, config, slug):
|
|
|
192
216
|
app_folder_name = re.sub("[ \/]", "-", app_folder_name)
|
|
193
217
|
app_folder_name = re.sub("[\"'`,\[\]\(\)]", "", app_folder_name)
|
|
194
218
|
working_dir_path = Path(repo.working_dir).absolute()
|
|
219
|
+
should_remove_dir = None
|
|
195
220
|
if config.get("type", "app") == "client_side_app":
|
|
221
|
+
gui_folder_path = config["gui_folder_path"]
|
|
222
|
+
gui_folder_path = working_dir_path / gui_folder_path
|
|
223
|
+
if not dir_exists(gui_folder_path):
|
|
224
|
+
should_remove_dir = gui_folder_path
|
|
225
|
+
# if gui folder is empty, need to render it
|
|
226
|
+
with cd(str(working_dir_path), add_to_path=True):
|
|
227
|
+
exec(open("sly_sdk/render.py", "r").read(), {"__name__": "__main__"})
|
|
228
|
+
file_paths.extend(
|
|
229
|
+
[Path(p).absolute() for p in list_files_recursively(str(gui_folder_path))]
|
|
230
|
+
)
|
|
196
231
|
archive_path = archive_folder + "/archive.tar"
|
|
197
232
|
write_mode = "w"
|
|
198
233
|
else:
|
|
@@ -205,6 +240,9 @@ def archive_application(repo: git.Repo, config, slug):
|
|
|
205
240
|
path.absolute(),
|
|
206
241
|
Path(app_folder_name).joinpath(path.relative_to(working_dir_path)),
|
|
207
242
|
)
|
|
243
|
+
if should_remove_dir is not None:
|
|
244
|
+
# remove gui folder if it was rendered
|
|
245
|
+
remove_dir(should_remove_dir)
|
|
208
246
|
return archive_path
|
|
209
247
|
|
|
210
248
|
|
supervisely/project/project.py
CHANGED
|
@@ -4432,23 +4432,29 @@ async def _download_project_async(
|
|
|
4432
4432
|
switch_size = kwargs.get("switch_size", 1.28 * 1024 * 1024)
|
|
4433
4433
|
# batch size for bulk download
|
|
4434
4434
|
batch_size = kwargs.get("batch_size", 100)
|
|
4435
|
-
# number of workers
|
|
4436
|
-
num_workers = kwargs.get("num_workers", 5)
|
|
4437
4435
|
|
|
4438
4436
|
if semaphore is None:
|
|
4439
4437
|
semaphore = api.get_default_semaphore()
|
|
4440
4438
|
|
|
4441
|
-
|
|
4442
|
-
|
|
4439
|
+
# number of workers
|
|
4440
|
+
num_workers = min(kwargs.get("num_workers", semaphore._value), 10)
|
|
4441
|
+
|
|
4442
|
+
async def worker(queue: asyncio.Queue, stop_event: asyncio.Event):
|
|
4443
|
+
while not stop_event.is_set():
|
|
4443
4444
|
task = await queue.get()
|
|
4444
4445
|
if task is None:
|
|
4445
4446
|
break
|
|
4446
|
-
|
|
4447
|
+
try:
|
|
4447
4448
|
await task
|
|
4448
|
-
|
|
4449
|
+
except Exception as e:
|
|
4450
|
+
logger.error(f"Error in _download_project_async worker: {e}")
|
|
4451
|
+
stop_event.set()
|
|
4452
|
+
finally:
|
|
4453
|
+
queue.task_done()
|
|
4449
4454
|
|
|
4450
4455
|
queue = asyncio.Queue()
|
|
4451
|
-
|
|
4456
|
+
stop_event = asyncio.Event()
|
|
4457
|
+
workers = [asyncio.create_task(worker(queue, stop_event)) for _ in range(num_workers)]
|
|
4452
4458
|
|
|
4453
4459
|
dataset_ids = set(dataset_ids) if (dataset_ids is not None) else None
|
|
4454
4460
|
project_fs = None
|
|
@@ -4588,6 +4594,10 @@ async def _download_project_async(
|
|
|
4588
4594
|
for _ in range(num_workers):
|
|
4589
4595
|
await queue.put(None)
|
|
4590
4596
|
await asyncio.gather(*workers)
|
|
4597
|
+
|
|
4598
|
+
if stop_event.is_set():
|
|
4599
|
+
raise RuntimeError("Download process was stopped due to an error in one of the workers.")
|
|
4600
|
+
|
|
4591
4601
|
try:
|
|
4592
4602
|
create_readme(dest_dir, project_id, api)
|
|
4593
4603
|
except Exception as e:
|
|
@@ -89,12 +89,12 @@ supervisely/app/development/sly-net.sh,sha256=-EVburj4NtS7Dw4OiwXXolYu9SXvui83F-
|
|
|
89
89
|
supervisely/app/fastapi/__init__.py,sha256=kNhkaGuBKn9-GNnPOmikIHqhjL-j66xmZaBbjCmXfAo,460
|
|
90
90
|
supervisely/app/fastapi/custom_static_files.py,sha256=5todaVIvUG9sAt6vu1IujJn8N7zTmFhVUfeCVbuXbvc,3391
|
|
91
91
|
supervisely/app/fastapi/dialog_window.html,sha256=ffaAxjK0TQRa7RrY5oA4uE6RzFuS0VnRG1pfoIzTqVM,1183
|
|
92
|
-
supervisely/app/fastapi/index.html,sha256=
|
|
92
|
+
supervisely/app/fastapi/index.html,sha256=wMMWSRCoVeOnIJYUHR6Aj-jebOuian963Si-cz5PibM,7951
|
|
93
93
|
supervisely/app/fastapi/no_html_main.html,sha256=NhQP7noyORBx72lFh1CQKgBRupkWjiq6Gaw-9Hkvg7c,37
|
|
94
94
|
supervisely/app/fastapi/offline.py,sha256=CwMMkJ1frD6wiZS-SEoNDtQ1UJcJe1Ob6ohE3r4CQL8,7414
|
|
95
95
|
supervisely/app/fastapi/request.py,sha256=NU7rKmxJ1pfkDZ7_yHckRcRAueJRQIqCor11UO2OHr8,766
|
|
96
|
-
supervisely/app/fastapi/subapp.py,sha256=
|
|
97
|
-
supervisely/app/fastapi/templating.py,sha256=
|
|
96
|
+
supervisely/app/fastapi/subapp.py,sha256=jjEfqNUjlwiNKFf9UKOHmVO1vGgvGjE-R_oyN0WFUbk,43561
|
|
97
|
+
supervisely/app/fastapi/templating.py,sha256=sxp8QMYfWd6ARDTl6c4JqY985-BSkM_WLxHEH2kv3bg,2929
|
|
98
98
|
supervisely/app/fastapi/utils.py,sha256=GZuTWLcVRGVx8TL3jVEYUOZIT2FawbwIe2kAOBLw9ho,398
|
|
99
99
|
supervisely/app/fastapi/websocket.py,sha256=TlRSPOAhRItTv1HGvdukK1ZvhRjMUxRa-lJlsRR9rJw,1308
|
|
100
100
|
supervisely/app/v1/__init__.py,sha256=OdU0PYv6hLwahYoyaLFO8m3cbJSchvPbqxuG1N3T734,848
|
|
@@ -549,7 +549,7 @@ supervisely/cli/project/project_download.py,sha256=dEznxE_MhLTYbU9KBbdmw-Ria1Knh
|
|
|
549
549
|
supervisely/cli/project/project_get.py,sha256=RWnMxuKd_WWhUlA5QEqI_9d4N6x8VDq0taPTWB8nxXc,689
|
|
550
550
|
supervisely/cli/project/project_upload.py,sha256=qA_0ktOpJxUUa_Hliwvny8-uIYDQBiuzHMq8nufbLd4,1416
|
|
551
551
|
supervisely/cli/release/__init__.py,sha256=5aDijgIIDsKFZVayq8anvv5ynWKhC4LZqAdESTKCW2c,335
|
|
552
|
-
supervisely/cli/release/release.py,sha256=
|
|
552
|
+
supervisely/cli/release/release.py,sha256=OtAi9g_2kvjp5lx4aiTE0JxczzJcaBtDFpHR-rHWFpE,9308
|
|
553
553
|
supervisely/cli/release/run.py,sha256=z6jDTVweCnlaIWsdUIN282B_JUqYZefJMIPLZnq2g9U,19899
|
|
554
554
|
supervisely/cli/task/__init__.py,sha256=n0ofJDqX3AMvvTz1umfBDfEUPDFzk5Htve3nnZFd7fs,67
|
|
555
555
|
supervisely/cli/task/task_set.py,sha256=KIGJ-X0iB7DzX3Ig8720FJh1WpohTVkkPk8HZt2rIzM,1337
|
|
@@ -1000,7 +1000,7 @@ supervisely/project/data_version.py,sha256=nknaWJSUCwoDyNG9_d1KA-GjzidhV9zd9Cn8c
|
|
|
1000
1000
|
supervisely/project/download.py,sha256=zb8sb4XZ6Qi3CP7fmtLRUAYzaxs_W0WnOfe2x3ZVRMs,24639
|
|
1001
1001
|
supervisely/project/pointcloud_episode_project.py,sha256=yiWdNBQiI6f1O9sr1pg8JHW6O-w3XUB1rikJNn3Oung,41866
|
|
1002
1002
|
supervisely/project/pointcloud_project.py,sha256=Kx1Vaes-krwG3BiRRtHRLQxb9G5m5bTHPN9IzRqmNWo,49399
|
|
1003
|
-
supervisely/project/project.py,sha256=
|
|
1003
|
+
supervisely/project/project.py,sha256=nKzuDw3DwcKtRg0fJyNrWE-XC7co0x3HTsAUWN8B2QI,189088
|
|
1004
1004
|
supervisely/project/project_meta.py,sha256=26s8IiHC5Pg8B1AQi6_CrsWteioJP2in00cRNe8QlW0,51423
|
|
1005
1005
|
supervisely/project/project_settings.py,sha256=NLThzU_DCynOK6hkHhVdFyezwprn9UqlnrLDe_3qhkY,9347
|
|
1006
1006
|
supervisely/project/project_type.py,sha256=_3RqW2CnDBKFOvSIrQT1RJQaiHirs34_jiQS8CkwCpo,530
|
|
@@ -1062,9 +1062,9 @@ supervisely/worker_proto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
|
|
|
1062
1062
|
supervisely/worker_proto/worker_api_pb2.py,sha256=VQfi5JRBHs2pFCK1snec3JECgGnua3Xjqw_-b3aFxuM,59142
|
|
1063
1063
|
supervisely/worker_proto/worker_api_pb2_grpc.py,sha256=3BwQXOaP9qpdi0Dt9EKG--Lm8KGN0C5AgmUfRv77_Jk,28940
|
|
1064
1064
|
supervisely_lib/__init__.py,sha256=7-3QnN8Zf0wj8NCr2oJmqoQWMKKPKTECvjH9pd2S5vY,159
|
|
1065
|
-
supervisely-6.73.
|
|
1066
|
-
supervisely-6.73.
|
|
1067
|
-
supervisely-6.73.
|
|
1068
|
-
supervisely-6.73.
|
|
1069
|
-
supervisely-6.73.
|
|
1070
|
-
supervisely-6.73.
|
|
1065
|
+
supervisely-6.73.273.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
1066
|
+
supervisely-6.73.273.dist-info/METADATA,sha256=uQxOZ2st0ZkJaK6YX4oZ5bVvX5YfFgrD9izZG_8oIxM,33573
|
|
1067
|
+
supervisely-6.73.273.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
|
1068
|
+
supervisely-6.73.273.dist-info/entry_points.txt,sha256=U96-5Hxrp2ApRjnCoUiUhWMqijqh8zLR03sEhWtAcms,102
|
|
1069
|
+
supervisely-6.73.273.dist-info/top_level.txt,sha256=kcFVwb7SXtfqZifrZaSE3owHExX4gcNYe7Q2uoby084,28
|
|
1070
|
+
supervisely-6.73.273.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|