setta 0.0.14.dev1__py3-none-any.whl → 0.0.14.dev3__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.
- setta/__init__.py +1 -1
- setta/static/frontend/assets/{index-Dc8I4Z7x.js → index-B_D80dlv.js} +153 -153
- setta/static/frontend/index.html +1 -1
- setta/tasks/tasks.py +4 -1
- setta/tasks/utils.py +259 -116
- {setta-0.0.14.dev1.dist-info → setta-0.0.14.dev3.dist-info}/METADATA +1 -1
- {setta-0.0.14.dev1.dist-info → setta-0.0.14.dev3.dist-info}/RECORD +11 -11
- {setta-0.0.14.dev1.dist-info → setta-0.0.14.dev3.dist-info}/LICENSE +0 -0
- {setta-0.0.14.dev1.dist-info → setta-0.0.14.dev3.dist-info}/WHEEL +0 -0
- {setta-0.0.14.dev1.dist-info → setta-0.0.14.dev3.dist-info}/entry_points.txt +0 -0
- {setta-0.0.14.dev1.dist-info → setta-0.0.14.dev3.dist-info}/top_level.txt +0 -0
setta/static/frontend/index.html
CHANGED
@@ -14,7 +14,7 @@
|
|
14
14
|
<meta name="description" content="setta" />
|
15
15
|
|
16
16
|
<title>setta.dev</title>
|
17
|
-
<script type="module" crossorigin src="/static/assets/index-
|
17
|
+
<script type="module" crossorigin src="/static/assets/index-B_D80dlv.js"></script>
|
18
18
|
<link rel="stylesheet" crossorigin href="/static/assets/index-DQjclEVk.css">
|
19
19
|
</head>
|
20
20
|
<body>
|
setta/tasks/tasks.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import asyncio
|
2
2
|
import copy
|
3
|
+
import json
|
3
4
|
import logging
|
4
5
|
import time
|
5
6
|
from typing import Dict
|
@@ -73,6 +74,7 @@ class Tasks:
|
|
73
74
|
# Create a list of tasks to run concurrently
|
74
75
|
tasks = []
|
75
76
|
results = []
|
77
|
+
message.content = {tuple(json.loads(k)): v for k, v in message.content.items()}
|
76
78
|
|
77
79
|
for sp_key, sp_info in self.in_memory_subprocesses.items():
|
78
80
|
if (subprocess_key and sp_key != subprocess_key) or (
|
@@ -80,7 +82,6 @@ class Tasks:
|
|
80
82
|
):
|
81
83
|
continue
|
82
84
|
for fn_name, fnInfo in sp_info["fnInfo"].items():
|
83
|
-
# TODO: there's a bug where fnInfo["dependencies"] contains tuples and message.content.keys() are strings
|
84
85
|
if (
|
85
86
|
call_all
|
86
87
|
or None in fnInfo["dependencies"]
|
@@ -150,6 +151,8 @@ class Tasks:
|
|
150
151
|
sp = self.in_memory_subprocesses.get(subprocess_key, {}).get("subprocess")
|
151
152
|
if sp:
|
152
153
|
sp.close()
|
154
|
+
del self.in_memory_subprocesses[subprocess_key]
|
155
|
+
|
153
156
|
sp = SettaInMemoryFnSubprocess(
|
154
157
|
self.stop_event, self.websockets, c["subprocessStartMethod"]
|
155
158
|
)
|
setta/tasks/utils.py
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
import asyncio
|
2
2
|
import importlib.util
|
3
|
-
import json
|
4
3
|
import logging
|
5
4
|
import multiprocessing
|
6
5
|
import queue
|
@@ -8,6 +7,7 @@ import sys
|
|
8
7
|
import threading
|
9
8
|
import traceback
|
10
9
|
import uuid
|
10
|
+
from collections import defaultdict
|
11
11
|
|
12
12
|
from setta.tasks.fns.utils import TaskDefinition
|
13
13
|
from setta.utils.constants import CWD
|
@@ -16,35 +16,6 @@ from setta.utils.utils import nested_access
|
|
16
16
|
logger = logging.getLogger(__name__)
|
17
17
|
|
18
18
|
|
19
|
-
def import_code_from_string(code_string, module_name=None, add_to_sys_modules=True):
|
20
|
-
# Generate a unique module name if one isn't provided
|
21
|
-
if module_name is None:
|
22
|
-
module_name = f"setta_dynamic_module_{uuid.uuid4().hex}"
|
23
|
-
|
24
|
-
# Add current directory to sys.path if it's not already there
|
25
|
-
current_dir = str(CWD)
|
26
|
-
if current_dir not in sys.path:
|
27
|
-
sys.path.insert(0, current_dir)
|
28
|
-
|
29
|
-
spec = importlib.util.spec_from_loader(module_name, loader=None)
|
30
|
-
|
31
|
-
# Create a new module based on the spec
|
32
|
-
module = importlib.util.module_from_spec(spec)
|
33
|
-
|
34
|
-
# Optionally add the module to sys.modules
|
35
|
-
if add_to_sys_modules:
|
36
|
-
print(f"adding {module_name} to sys.modules", flush=True)
|
37
|
-
sys.modules[module_name] = module
|
38
|
-
|
39
|
-
# Compile the code string
|
40
|
-
code_object = compile(code_string, module_name, "exec")
|
41
|
-
|
42
|
-
# Execute the compiled code object in the module's namespace
|
43
|
-
exec(code_object, module.__dict__)
|
44
|
-
|
45
|
-
return module
|
46
|
-
|
47
|
-
|
48
19
|
class SettaInMemoryFnSubprocess:
|
49
20
|
def __init__(self, stop_event, websockets, start_method):
|
50
21
|
logger.debug(
|
@@ -69,20 +40,20 @@ class SettaInMemoryFnSubprocess:
|
|
69
40
|
self.start_stdout_processor_task()
|
70
41
|
|
71
42
|
def _subprocess_main(self):
|
72
|
-
"""Main loop in subprocess that handles all requests"""
|
43
|
+
"""Main loop in subprocess that handles all requests with parallel function execution"""
|
73
44
|
# Initialize store for imported modules
|
74
45
|
fns_dict = {}
|
75
46
|
cache = {}
|
76
47
|
|
77
|
-
|
78
|
-
|
79
|
-
self.stdout_pipe = stdout_pipe
|
48
|
+
# Message queues per function
|
49
|
+
fn_message_queues = defaultdict(queue.Queue)
|
80
50
|
|
81
|
-
|
82
|
-
|
51
|
+
# Create a lock for thread-safe operations
|
52
|
+
lock = threading.RLock()
|
53
|
+
send_lock = threading.Lock()
|
83
54
|
|
84
|
-
|
85
|
-
|
55
|
+
# Function worker threads
|
56
|
+
fn_workers = {}
|
86
57
|
|
87
58
|
# Redirect stdout as soon as subprocess starts
|
88
59
|
output_capture = OutputCapture(self.stdout_child_conn)
|
@@ -92,9 +63,16 @@ class SettaInMemoryFnSubprocess:
|
|
92
63
|
while True:
|
93
64
|
msg = self.child_conn.recv() # Wait for requests
|
94
65
|
msg_type = msg["type"]
|
95
|
-
return_message_type = None
|
96
66
|
|
97
67
|
if msg_type == "shutdown":
|
68
|
+
# Signal all worker threads to stop
|
69
|
+
for fn_name in fn_workers:
|
70
|
+
fn_message_queues[fn_name].put(None)
|
71
|
+
|
72
|
+
# Wait for all worker threads to finish (with timeout)
|
73
|
+
for fn_name, worker in fn_workers.items():
|
74
|
+
worker.join(timeout=1.0)
|
75
|
+
|
98
76
|
break
|
99
77
|
|
100
78
|
try:
|
@@ -105,108 +83,217 @@ class SettaInMemoryFnSubprocess:
|
|
105
83
|
module_name = to_import["module_name"]
|
106
84
|
# Import and store module
|
107
85
|
module = import_code_from_string(code, module_name)
|
108
|
-
|
109
|
-
|
86
|
+
with lock:
|
87
|
+
added_fn_names = add_fns_from_module(
|
88
|
+
fns_dict, module, module_name
|
89
|
+
)
|
90
|
+
for k in added_fn_names:
|
91
|
+
cache[k] = msg["exporter_obj"]
|
92
|
+
dependencies[k] = get_task_metadata(
|
93
|
+
fns_dict[k], cache[k]
|
94
|
+
)
|
95
|
+
# Start a worker thread for each function
|
96
|
+
self._start_worker_for_fn(
|
97
|
+
k,
|
98
|
+
fn_workers,
|
99
|
+
fn_message_queues,
|
100
|
+
fns_dict,
|
101
|
+
cache,
|
102
|
+
lock,
|
103
|
+
send_lock,
|
104
|
+
self.child_conn,
|
105
|
+
)
|
106
|
+
|
107
|
+
with send_lock:
|
108
|
+
self.child_conn.send(
|
109
|
+
{
|
110
|
+
"status": "success",
|
111
|
+
"content": dependencies,
|
112
|
+
}
|
110
113
|
)
|
111
|
-
for k in added_fn_names:
|
112
|
-
cache[k] = msg["exporter_obj"]
|
113
|
-
dependencies[k] = get_task_metadata(fns_dict[k], cache[k])
|
114
114
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
115
|
+
elif msg_type == "call" or msg_type == "call_with_new_exporter_obj":
|
116
|
+
fn_name = msg["fn_name"]
|
117
|
+
|
118
|
+
# Start a worker for this function if needed
|
119
|
+
self._start_worker_for_fn(
|
120
|
+
fn_name,
|
121
|
+
fn_workers,
|
122
|
+
fn_message_queues,
|
123
|
+
fns_dict,
|
124
|
+
cache,
|
125
|
+
lock,
|
126
|
+
send_lock,
|
127
|
+
self.child_conn,
|
120
128
|
)
|
121
129
|
|
122
|
-
|
123
|
-
|
124
|
-
msg, fns_dict, cache
|
125
|
-
)
|
126
|
-
self.child_conn.send(
|
127
|
-
{
|
128
|
-
"status": "success",
|
129
|
-
"content": result,
|
130
|
-
"messageType": return_message_type,
|
131
|
-
}
|
132
|
-
)
|
130
|
+
# Add the message to the function's queue
|
131
|
+
fn_message_queues[fn_name].put(msg)
|
133
132
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
result, return_message_type = self.call_imported_fn(
|
138
|
-
msg, fns_dict, cache
|
139
|
-
)
|
133
|
+
except Exception as e:
|
134
|
+
traceback.print_exc()
|
135
|
+
with send_lock:
|
140
136
|
self.child_conn.send(
|
141
137
|
{
|
142
|
-
"status": "
|
143
|
-
"
|
144
|
-
"messageType":
|
138
|
+
"status": "error",
|
139
|
+
"error": str(e),
|
140
|
+
"messageType": None,
|
145
141
|
}
|
146
142
|
)
|
147
143
|
|
144
|
+
def _worker_thread(
|
145
|
+
self, fn_name, fn_message_queues, fns_dict, cache, lock, send_lock, child_conn
|
146
|
+
):
|
147
|
+
"""Worker thread that processes messages for a specific function"""
|
148
|
+
while True:
|
149
|
+
try:
|
150
|
+
# Get a message from the queue
|
151
|
+
msg = fn_message_queues[fn_name].get()
|
152
|
+
|
153
|
+
if msg is None: # Sentinel value to stop the thread
|
154
|
+
break
|
155
|
+
|
156
|
+
msg_type = msg["type"]
|
157
|
+
return_message_type = None
|
158
|
+
|
159
|
+
if msg_type == "call" or msg_type == "call_with_new_exporter_obj":
|
160
|
+
try:
|
161
|
+
# Handle updating exporter_obj for call_with_new_exporter_obj
|
162
|
+
if msg_type == "call_with_new_exporter_obj":
|
163
|
+
with lock:
|
164
|
+
cache[fn_name] = msg["other_data"]["exporter_obj"]
|
165
|
+
|
166
|
+
# Get a thread-safe copy of what we need
|
167
|
+
with lock:
|
168
|
+
in_memory_fn_obj = fns_dict[fn_name]
|
169
|
+
exporter_obj = cache.get(fn_name)
|
170
|
+
|
171
|
+
# Process message
|
172
|
+
message_content = process_message(msg["message"], exporter_obj)
|
173
|
+
|
174
|
+
# Call function
|
175
|
+
result = in_memory_fn_obj.fn(message_content)
|
176
|
+
return_message_type = in_memory_fn_obj.return_message_type
|
177
|
+
|
178
|
+
# Send result back
|
179
|
+
with send_lock:
|
180
|
+
child_conn.send(
|
181
|
+
{
|
182
|
+
"status": "success",
|
183
|
+
"content": result,
|
184
|
+
"messageType": return_message_type,
|
185
|
+
}
|
186
|
+
)
|
187
|
+
except Exception as e:
|
188
|
+
traceback.print_exc()
|
189
|
+
with send_lock:
|
190
|
+
child_conn.send(
|
191
|
+
{
|
192
|
+
"status": "error",
|
193
|
+
"error": str(e),
|
194
|
+
"messageType": return_message_type,
|
195
|
+
}
|
196
|
+
)
|
197
|
+
|
198
|
+
# Mark task as done
|
199
|
+
fn_message_queues[fn_name].task_done()
|
200
|
+
|
148
201
|
except Exception as e:
|
149
202
|
traceback.print_exc()
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
203
|
+
print(f"Error in worker thread for {fn_name}: {e}", flush=True)
|
204
|
+
|
205
|
+
def _start_worker_for_fn(
|
206
|
+
self,
|
207
|
+
fn_name,
|
208
|
+
fn_workers,
|
209
|
+
fn_message_queues,
|
210
|
+
fns_dict,
|
211
|
+
cache,
|
212
|
+
lock,
|
213
|
+
send_lock,
|
214
|
+
child_conn,
|
215
|
+
):
|
216
|
+
"""Start a worker thread for a function if not already running"""
|
217
|
+
if fn_name not in fn_workers or not fn_workers[fn_name].is_alive():
|
218
|
+
worker = threading.Thread(
|
219
|
+
target=self._worker_thread,
|
220
|
+
args=(
|
221
|
+
fn_name,
|
222
|
+
fn_message_queues,
|
223
|
+
fns_dict,
|
224
|
+
cache,
|
225
|
+
lock,
|
226
|
+
send_lock,
|
227
|
+
child_conn,
|
228
|
+
),
|
229
|
+
daemon=True,
|
230
|
+
name=f"worker-{fn_name}",
|
231
|
+
)
|
232
|
+
fn_workers[fn_name] = worker
|
233
|
+
worker.start()
|
165
234
|
|
166
235
|
def close(self):
|
167
236
|
try:
|
168
237
|
logger.debug("Initiating shutdown sequence")
|
169
|
-
self.parent_conn.send({"type": "shutdown"})
|
170
|
-
self.process.join(timeout=2) # Add timeout to process join
|
171
238
|
|
239
|
+
# Set our stop event - this signals all tasks to stop
|
240
|
+
self.stop_event.set()
|
241
|
+
|
242
|
+
# Send shutdown message to the subprocess
|
243
|
+
try:
|
244
|
+
self.parent_conn.send({"type": "shutdown"})
|
245
|
+
except (BrokenPipeError, EOFError):
|
246
|
+
# Pipe might already be closed, that's okay
|
247
|
+
pass
|
248
|
+
|
249
|
+
# Join the process with timeout
|
250
|
+
self.process.join(timeout=2)
|
251
|
+
|
252
|
+
# If still alive, escalate to terminate
|
172
253
|
if self.process.is_alive():
|
173
|
-
logger.debug(
|
254
|
+
logger.debug(
|
255
|
+
"Process still alive after graceful shutdown, forcing termination"
|
256
|
+
)
|
174
257
|
self.process.terminate()
|
175
258
|
self.process.join(timeout=1)
|
176
|
-
except Exception as e:
|
177
|
-
logger.debug(f"Error during process shutdown: {e}")
|
178
259
|
|
179
|
-
|
180
|
-
|
260
|
+
# Last resort: kill
|
261
|
+
if self.process.is_alive():
|
262
|
+
logger.debug(
|
263
|
+
"Process still alive after terminate, killing forcefully"
|
264
|
+
)
|
265
|
+
self.process.kill()
|
266
|
+
self.process.join(timeout=1)
|
181
267
|
|
182
|
-
|
183
|
-
|
184
|
-
self.parent_conn,
|
185
|
-
self.child_conn,
|
186
|
-
self.stdout_parent_conn,
|
187
|
-
self.stdout_child_conn,
|
188
|
-
]:
|
189
|
-
conn.close()
|
268
|
+
except Exception as e:
|
269
|
+
logger.exception(f"Error during process shutdown: {e}")
|
190
270
|
|
191
|
-
|
271
|
+
# Now handle the async tasks and threads
|
272
|
+
try:
|
273
|
+
# Cancel the stdout processor task if it exists
|
274
|
+
if self.stdout_processor_task:
|
275
|
+
self.stdout_processor_task.cancel()
|
276
|
+
|
277
|
+
# Close all connections - this will cause pending operations to fail fast
|
278
|
+
for conn in [
|
279
|
+
self.parent_conn,
|
280
|
+
self.child_conn,
|
281
|
+
self.stdout_parent_conn,
|
282
|
+
self.stdout_child_conn,
|
283
|
+
]:
|
284
|
+
try:
|
285
|
+
conn.close()
|
286
|
+
except:
|
287
|
+
pass
|
192
288
|
|
193
|
-
|
194
|
-
|
289
|
+
# Join the stdout thread with timeout
|
290
|
+
if self.stdout_thread and self.stdout_thread.is_alive():
|
291
|
+
self.stdout_thread.join(timeout=2)
|
292
|
+
if self.stdout_thread.is_alive():
|
293
|
+
logger.debug("Stdout thread failed to terminate within timeout")
|
195
294
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
def process_message(self, fn_name, message, cache):
|
200
|
-
if fn_name in cache:
|
201
|
-
exporter_obj = cache[fn_name]
|
202
|
-
for k, v in message.content.items():
|
203
|
-
nice_str = exporter_obj.var_name_mapping.get(tuple(json.loads(k)))
|
204
|
-
if not nice_str:
|
205
|
-
continue
|
206
|
-
p_dict, key = nested_access(exporter_obj.output, nice_str)
|
207
|
-
p_dict[key] = v
|
208
|
-
message.content = exporter_obj.output
|
209
|
-
return message.content
|
295
|
+
except Exception as e:
|
296
|
+
logger.exception(f"Error during resource cleanup: {e}")
|
210
297
|
|
211
298
|
def start_stdout_processor_task(self):
|
212
299
|
if self.stdout_processor_task is None or self.stdout_processor_task.done():
|
@@ -291,3 +378,59 @@ def get_task_metadata(in_memory_fn, exporter_obj):
|
|
291
378
|
exporter_obj.var_name_reverse_mapping[d] for d in in_memory_fn.dependencies
|
292
379
|
)
|
293
380
|
return dependencies
|
381
|
+
|
382
|
+
|
383
|
+
# Class for capturing and redirecting stdout/stderr
|
384
|
+
class OutputCapture:
|
385
|
+
def __init__(self, stdout_pipe):
|
386
|
+
self.stdout_pipe = stdout_pipe
|
387
|
+
self.lock = threading.Lock()
|
388
|
+
|
389
|
+
def write(self, text):
|
390
|
+
with self.lock:
|
391
|
+
self.stdout_pipe.send(text)
|
392
|
+
|
393
|
+
def flush(self):
|
394
|
+
pass
|
395
|
+
|
396
|
+
|
397
|
+
def process_message(message, exporter_obj):
|
398
|
+
"""Process a message before passing it to a function"""
|
399
|
+
if exporter_obj:
|
400
|
+
for k, v in message.content.items():
|
401
|
+
nice_str = exporter_obj.var_name_mapping.get(k)
|
402
|
+
if not nice_str:
|
403
|
+
continue
|
404
|
+
p_dict, key = nested_access(exporter_obj.output, nice_str)
|
405
|
+
p_dict[key] = v
|
406
|
+
return exporter_obj.output
|
407
|
+
return message.content
|
408
|
+
|
409
|
+
|
410
|
+
def import_code_from_string(code_string, module_name=None, add_to_sys_modules=True):
|
411
|
+
# Generate a unique module name if one isn't provided
|
412
|
+
if module_name is None:
|
413
|
+
module_name = f"setta_dynamic_module_{uuid.uuid4().hex}"
|
414
|
+
|
415
|
+
# Add current directory to sys.path if it's not already there
|
416
|
+
current_dir = str(CWD)
|
417
|
+
if current_dir not in sys.path:
|
418
|
+
sys.path.insert(0, current_dir)
|
419
|
+
|
420
|
+
spec = importlib.util.spec_from_loader(module_name, loader=None)
|
421
|
+
|
422
|
+
# Create a new module based on the spec
|
423
|
+
module = importlib.util.module_from_spec(spec)
|
424
|
+
|
425
|
+
# Optionally add the module to sys.modules
|
426
|
+
if add_to_sys_modules:
|
427
|
+
print(f"adding {module_name} to sys.modules", flush=True)
|
428
|
+
sys.modules[module_name] = module
|
429
|
+
|
430
|
+
# Compile the code string
|
431
|
+
code_object = compile(code_string, module_name, "exec")
|
432
|
+
|
433
|
+
# Execute the compiled code object in the module's namespace
|
434
|
+
exec(code_object, module.__dict__)
|
435
|
+
|
436
|
+
return module
|
@@ -1,4 +1,4 @@
|
|
1
|
-
setta/__init__.py,sha256=
|
1
|
+
setta/__init__.py,sha256=dRyAeVBboRTo_BMS4gP2ZewakrwbpbNaV3_dLZTmbgQ,28
|
2
2
|
setta/server.py,sha256=q4w9WG7SuLxwYtgXUCQyLt7t_HLmQV4y5abqvm7-uEA,4861
|
3
3
|
setta/start.py,sha256=5sMZ7WH3KV9Q0v186PsaYqsWOz7hebyrpXbBOp9wQww,3589
|
4
4
|
setta/cli/__init__.py,sha256=UxZG_VOMuF6lEBT3teUgTS9ulsK3wt3Gu3BbAQiAmt8,47
|
@@ -109,7 +109,7 @@ setta/static/frontend/browserconfig.xml,sha256=w0iw1t89kA7-965LTfyLYrFzewTQnUWE_
|
|
109
109
|
setta/static/frontend/favicon-16x16.png,sha256=q67Crpy8s3wryu7Y3kffPeysN99Lt4XeFygXhPKize8,740
|
110
110
|
setta/static/frontend/favicon-32x32.png,sha256=4NKXYticYdMrRHmVveHjxqnBU1HWgBT5JyJG8lx3BNE,1027
|
111
111
|
setta/static/frontend/favicon.ico,sha256=02qhEBLsvsgBTZX6dcZElMyivlvrR7Yr6wB8ItEZFsc,15086
|
112
|
-
setta/static/frontend/index.html,sha256=
|
112
|
+
setta/static/frontend/index.html,sha256=F8-JCfCuTlOXXGmwFhCc7p-pGOdqZlgKLzupLNCSxHc,1298
|
113
113
|
setta/static/frontend/manifest.json,sha256=ULPYw5A68_eNhxuUVXqxT045yhkurKPSz6hjyGcnmhQ,492
|
114
114
|
setta/static/frontend/mstile-144x144.png,sha256=wQqckmRWre2NCCevevI3rv4j0tcduVMkpYr2tPj73cs,2692
|
115
115
|
setta/static/frontend/mstile-150x150.png,sha256=FUwy6PipTofnhmJB5CdXWYgwy-2inq_sIOdOwdDklcY,2674
|
@@ -184,8 +184,8 @@ setta/static/frontend/assets/cormorant-garamond-cyrillic-ext-700-italic-gsr366qd
|
|
184
184
|
setta/static/frontend/assets/cormorant-garamond-latin-700-italic-BQbwEFjx.woff2,sha256=C8U-EgDBT8MpU4FpUNBJdybVpKvRhg_3WDpUDCw9XZg,20348
|
185
185
|
setta/static/frontend/assets/cormorant-garamond-latin-ext-700-italic-DnnS5iSC.woff2,sha256=Ulc44CPXdUiI5dY86W76HLk7801Fm9_QywCV-8GRtFU,17240
|
186
186
|
setta/static/frontend/assets/cormorant-garamond-vietnamese-700-italic-2_nTgjbG.woff2,sha256=mVYwN54qI0RLXqyrDGPUNpBHWSJDKjgUyBRWa2FJ_ao,5248
|
187
|
+
setta/static/frontend/assets/index-B_D80dlv.js,sha256=FMJmhUHbA3QfKJ_EU9UzcSwxZw9KI5X3WirWAfrtBUE,3082364
|
187
188
|
setta/static/frontend/assets/index-DQjclEVk.css,sha256=uIx7VJi9TIDdzOMllLQNKxOMTytUkdRv9LVJyiB190g,238315
|
188
|
-
setta/static/frontend/assets/index-Dc8I4Z7x.js,sha256=Jm4TDPmcXViJsYacbh4zZZdf9ICR0__pV71NSrkMDhA,3082204
|
189
189
|
setta/static/frontend/assets/inter-all-400-normal-ByZ5TkcW.woff,sha256=BU8S0GmcIMyYte4ESEdQJO-WvL2Rb-38m1n0ujdbYxI,128624
|
190
190
|
setta/static/frontend/assets/inter-all-600-normal-BQl_S1BW.woff,sha256=wDdp5VNyQL_IbxcPThD2qI-ETg_QKj7AmCwMCjqDfLE,139072
|
191
191
|
setta/static/frontend/assets/inter-all-800-normal-BdAoPad8.woff,sha256=FdxuS9xuVumB5nbVcCXyt3IWqzS4Z75qiRz_0FV5al0,139120
|
@@ -230,8 +230,8 @@ setta/static/seed/.DS_Store,sha256=ENxJvDQd7Te_U8gExcXtHE-mAeBUYOHELRfDWgN1NmA,6
|
|
230
230
|
setta/static/seed/examples/.DS_Store,sha256=1lFlJ5EFymdzGAUAaI30vcaaLHt3F1LwpG7xILf9jsM,6148
|
231
231
|
setta/tasks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
232
232
|
setta/tasks/task_runner.py,sha256=gMXpfZWFMQbix2MfrHVCKB7BxQCjO8JH2P8cxUmt1ms,849
|
233
|
-
setta/tasks/tasks.py,sha256=
|
234
|
-
setta/tasks/utils.py,sha256=
|
233
|
+
setta/tasks/tasks.py,sha256=uG-S3jN9qZEolHtXkJZ4LMi-8LrNPctQR6TVWPlyeTs,10206
|
234
|
+
setta/tasks/utils.py,sha256=cTmHJGPk6HHbl7nNTPV2KaTugkdSRJTow0z4A05b0lg,15901
|
235
235
|
setta/tasks/fns/__init__.py,sha256=JhGzzQGaT9BWtF3pOmguh6pzIF9kdG3jdDNLyYZ2w7g,461
|
236
236
|
setta/tasks/fns/codeAreaAutocomplete.py,sha256=gJ5JbjkWDyTothr-UF-YlOxrbVzj2iyOVK7XD3lfhSQ,6416
|
237
237
|
setta/tasks/fns/codeAreaFindTemplateVars.py,sha256=vD9rY8VNPavv6VKa1bnxRPPRDNvFQy6mPIZRl-_3GnY,3708
|
@@ -252,9 +252,9 @@ setta/utils/generate_new_filename.py,sha256=KBLX6paDmTvXR-027TpqQkfijIXc7mCfhen-
|
|
252
252
|
setta/utils/section_contents.py,sha256=V2HQPik6DfSXw4j7IalbP5AZ3OEGCbtL5ub3xL-Q_Qo,4141
|
253
253
|
setta/utils/utils.py,sha256=KjzcvgM3Ab3IcE8vaWYtgBpwzPLKg0LmblnHLoYZJHM,9164
|
254
254
|
setta/utils/websocket_manager.py,sha256=MBIMI8xxOFQF4lT3on4pupi1ttEWXdWPV4fI2YP_UJU,3925
|
255
|
-
setta-0.0.14.
|
256
|
-
setta-0.0.14.
|
257
|
-
setta-0.0.14.
|
258
|
-
setta-0.0.14.
|
259
|
-
setta-0.0.14.
|
260
|
-
setta-0.0.14.
|
255
|
+
setta-0.0.14.dev3.dist-info/LICENSE,sha256=us9fuCq9wmiZVzayjKxNZ2iJYF6dROe0Qp57ToCO7XU,11361
|
256
|
+
setta-0.0.14.dev3.dist-info/METADATA,sha256=_B3NlxJtJjD-3RX-EifIfhK5bIgRfFbzFnCgNsOTL04,7517
|
257
|
+
setta-0.0.14.dev3.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
|
258
|
+
setta-0.0.14.dev3.dist-info/entry_points.txt,sha256=P0qCESy9fWF2q1EQ9JufGldCSnPHplDPn8J6Bgk5hB0,42
|
259
|
+
setta-0.0.14.dev3.dist-info/top_level.txt,sha256=8G4lmRzVOnJ11_DescPVHE6MQZH-o06A0nGsDDV2ngY,6
|
260
|
+
setta-0.0.14.dev3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|