setta 0.0.3.dev3__py3-none-any.whl → 0.0.3.dev5__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -15,8 +15,8 @@
15
15
 
16
16
 
17
17
  <title>setta.dev</title>
18
- <script type="module" crossorigin src="/static/assets/index-73adf0a9.js"></script>
19
- <link rel="stylesheet" href="/static/assets/index-1d4b4ecf.css">
18
+ <script type="module" crossorigin src="/static/assets/index-1f218da9.js"></script>
19
+ <link rel="stylesheet" href="/static/assets/index-af271c9f.css">
20
20
  </head>
21
21
  <body>
22
22
  <noscript>You need to enable JavaScript to run this app.</noscript>
setta/tasks/tasks.py CHANGED
@@ -1,10 +1,9 @@
1
1
  import asyncio
2
2
  import logging
3
- import queue
4
- import threading
5
3
  from typing import Dict
6
4
 
7
5
  from setta.database.utils import create_new_id
6
+ from setta.utils.constants import C
8
7
 
9
8
  from . import fns
10
9
  from .fns.utils import TaskDefinition, TaskMessage
@@ -20,75 +19,31 @@ class Tasks:
20
19
  self.task_runner = TaskRunner()
21
20
  self.cache = {}
22
21
  self.fns: Dict[str, TaskDefinition] = {}
23
- self.in_memory_subprocess = SettaInMemoryFnSubprocess()
24
- self.websockets = [] # Store the websocket connections
22
+ self.in_memory_subprocesses = {}
23
+ self.websockets = []
24
+ self.stop_event = asyncio.Event()
25
25
  add_fns_from_module(self.fns, fns)
26
26
 
27
- # Start stdout listener thread
28
- self._stop_event = asyncio.Event()
29
- self.stdout_queue = queue.Queue() # regular Queue
30
- self._stdout_processor_task = None
31
- self.stdout_thread = threading.Thread(target=self._stdout_listener, daemon=True)
32
- self.stdout_thread.start()
33
-
34
- # Backend Changes (Tasks class)
35
27
  async def connect(self, websocket):
36
28
  # Accept the new connection
37
29
  await websocket.accept()
38
30
  self.websockets.append(websocket)
39
-
40
- # Start the processor task if it's not running
41
- if self._stdout_processor_task is None or self._stdout_processor_task.done():
42
- self._stdout_processor_task = asyncio.create_task(
43
- self._process_stdout_queue()
44
- )
31
+ for k, v in self.in_memory_subprocesses.items():
32
+ v["subprocess"].start_stdout_processor_task()
33
+ logger.debug(f"listening to subprocess {k}")
45
34
 
46
35
  async def disconnect(self, websocket):
47
36
  self.websockets.remove(websocket)
48
37
  if len(self.websockets) == 0:
49
- # Cancel the processor task
50
- if self._stdout_processor_task and not self._stdout_processor_task.done():
51
- self._stdout_processor_task.cancel()
52
- try:
53
- await self._stdout_processor_task
54
- except asyncio.CancelledError:
55
- pass
56
- self._stdout_processor_task = None
57
-
58
- def _stdout_listener(self):
59
- while not self._stop_event.is_set():
60
- try:
61
- stdout_data = self.in_memory_subprocess.stdout_parent_conn.recv()
62
- self.stdout_queue.put(stdout_data) # simple put, no async needed
63
- except Exception as e:
64
- if self._stop_event.is_set():
65
- break
66
- logger.debug(f"Error in stdout listener: {e}")
67
-
68
- async def _process_stdout_queue(self):
69
- while not self._stop_event.is_set():
70
- try:
71
- if self._stop_event.is_set():
72
- break
73
- if len(self.websockets) > 0:
74
- stdout_data = self.stdout_queue.get_nowait()
75
- stdout_data = stdout_data.replace("\n", "\r\n")
76
- for w in self.websockets:
77
- await w.send_text(stdout_data)
78
- self.stdout_queue.task_done()
79
- except queue.Empty:
80
- await asyncio.sleep(0.1) # Check for connection every 100ms
81
- except asyncio.CancelledError:
82
- break
83
- except Exception as e:
84
- if self._stop_event.is_set():
85
- break
86
- logger.debug(f"Error processing stdout: {e}")
87
-
88
- async def __call__(self, fn_name, message: TaskMessage):
89
- if fn_name in self.fns:
90
- return await self.call_regular_fn(fn_name, message)
91
- return await self.call_in_memory_subprocess_fn(fn_name, message)
38
+ for v in self.in_memory_subprocesses.values():
39
+ await v["subprocess"].stop_stdout_processor_task()
40
+
41
+ async def __call__(
42
+ self, message_type, message: TaskMessage, websocket_manager=None
43
+ ):
44
+ if message_type == "inMemoryFn":
45
+ return await self.call_in_memory_subprocess_fn(message, websocket_manager)
46
+ return await self.call_regular_fn(message_type, message)
92
47
 
93
48
  async def call_regular_fn(self, fn_name, message: TaskMessage):
94
49
  fn = self.fns[fn_name]
@@ -101,52 +56,104 @@ class Tasks:
101
56
  result["messageType"] = fn.return_message_type
102
57
  return result
103
58
 
104
- async def call_in_memory_subprocess_fn(self, fn_name, message: TaskMessage):
105
- self.in_memory_subprocess.parent_conn.send(
106
- {"type": "call", "fn_name": fn_name, "message": message}
107
- )
108
- result = await self.task_runner.run(
109
- self.in_memory_subprocess.parent_conn.recv, [], RunType.THREAD
110
- )
111
- # if result["status"] == "success":
112
- # for x in result["content"]:
113
- # x.setdefault("sectionType", default_section_type(x["type"]))
114
- if result["status"] != "success":
115
- result["content"] = {}
116
-
117
- return {"content": result["content"], "messageType": result["messageType"]}
118
-
119
- async def add_custom_fns(self, code_list, to_cache):
120
- error_msgs = {}
121
- task_metadata = {}
122
- initial_content = []
123
- for c in code_list:
124
- # Send import request to subprocess
125
- self.in_memory_subprocess.parent_conn.send(
59
+ async def call_in_memory_subprocess_fn(
60
+ self, message: TaskMessage, websocket_manager=None, call_all=False
61
+ ):
62
+ # Create a list of tasks to run concurrently
63
+ tasks = []
64
+ results = []
65
+
66
+ for sp_info in self.in_memory_subprocesses.values():
67
+ for fn_name, dependencies in sp_info["dependencies"].items():
68
+ if (
69
+ call_all
70
+ or None in dependencies
71
+ or any(k in dependencies for k in message.content.keys())
72
+ ):
73
+ # Send message to subprocess
74
+ sp_info["subprocess"].parent_conn.send(
75
+ {"type": "call", "fn_name": fn_name, "message": message}
76
+ )
77
+
78
+ # Create task for receiving response
79
+ task = asyncio.create_task(
80
+ self._handle_subprocess_response(
81
+ message.id,
82
+ sp_info["subprocess"].parent_conn.recv,
83
+ websocket_manager,
84
+ results,
85
+ )
86
+ )
87
+ tasks.append(task)
88
+
89
+ # Wait for all tasks to complete concurrently
90
+ if tasks:
91
+ await asyncio.gather(*tasks)
92
+
93
+ if websocket_manager:
94
+ return {}
95
+
96
+ content = []
97
+ for r in results:
98
+ if r["content"]:
99
+ content.extend(r["content"])
100
+ return {"content": content, "messageType": C.WS_IN_MEMORY_FN_RETURN}
101
+
102
+ async def _handle_subprocess_response(
103
+ self, msg_id, recv_fn, websocket_manager, results
104
+ ):
105
+ # Run the receive function in a thread
106
+ result = await self.task_runner.run(recv_fn, [], RunType.THREAD)
107
+ if result["status"] == "success":
108
+ if websocket_manager is not None and result["content"]:
109
+ await websocket_manager.send_message_to_requester(
110
+ msg_id, result["content"], result["messageType"]
111
+ )
112
+ else:
113
+ results.append(result)
114
+
115
+ async def add_custom_fns(self, code_graph, to_cache):
116
+ for c in code_graph:
117
+ subprocess_key = c["subprocess_key"]
118
+ module_name = c["module_name"]
119
+ sp = self.in_memory_subprocesses.get(subprocess_key, {}).get("subprocess")
120
+ if not sp:
121
+ logger.debug(f"Creating new subprocess for {module_name}")
122
+ sp = SettaInMemoryFnSubprocess(self.stop_event, self.websockets)
123
+ self.in_memory_subprocesses[subprocess_key] = {
124
+ "subprocess": sp,
125
+ "dependencies": {},
126
+ }
127
+
128
+ sp.parent_conn.send(
126
129
  {
127
130
  "type": "import",
128
131
  "code": c["code"],
129
- "module_name": c["module_name"],
132
+ "module_name": module_name,
130
133
  "to_cache": to_cache,
131
134
  }
132
135
  )
133
- result = await self.task_runner.run(
134
- self.in_memory_subprocess.parent_conn.recv, [], RunType.THREAD
135
- )
136
+ result = await self.task_runner.run(sp.parent_conn.recv, [], RunType.THREAD)
137
+ sp_info = self.in_memory_subprocesses[subprocess_key]
138
+
136
139
  if result["status"] == "success":
137
- task_metadata.update(result["content"])
140
+ sp_info["dependencies"].update(result["content"])
138
141
  else:
139
- error_msgs[c["module_name"]] = result["error"]
142
+ # TODO: store error message and display on frontend?
143
+ pass
140
144
 
141
- for k in task_metadata.keys():
142
- task_output = await self(k, TaskMessage(id=create_new_id(), content={}))
143
- initial_content.extend(task_output["content"])
145
+ all_dependencies = set.union(*sp_info["dependencies"].values())
146
+ initial_result = await self.call_in_memory_subprocess_fn(
147
+ TaskMessage(id=create_new_id(), content={}), call_all=True
148
+ )
149
+
150
+ logger.debug(
151
+ f"self.in_memory_subprocesses keys: {self.in_memory_subprocesses.keys()}"
152
+ )
144
153
 
145
- return task_metadata, error_msgs, initial_content
154
+ return all_dependencies, initial_result["content"]
146
155
 
147
156
  def close(self):
148
- self._stop_event.set()
149
- self.in_memory_subprocess.close()
150
- self.stdout_thread.join()
151
- if self._stdout_processor_task:
152
- self._stdout_processor_task.cancel()
157
+ self.stop_event.set()
158
+ for v in self.in_memory_subprocesses.values():
159
+ v["subprocess"].close()
setta/tasks/utils.py CHANGED
@@ -1,7 +1,11 @@
1
+ import asyncio
1
2
  import importlib.util
2
3
  import json
4
+ import logging
3
5
  import multiprocessing
6
+ import queue
4
7
  import sys
8
+ import threading
5
9
  import traceback
6
10
  import uuid
7
11
 
@@ -9,6 +13,8 @@ from setta.tasks.fns.utils import TaskDefinition
9
13
  from setta.utils.constants import CWD
10
14
  from setta.utils.utils import nested_access
11
15
 
16
+ logger = logging.getLogger(__name__)
17
+
12
18
 
13
19
  def import_code_from_string(code_string, module_name=None, add_to_sys_modules=True):
14
20
  # Generate a unique module name if one isn't provided
@@ -16,9 +22,8 @@ def import_code_from_string(code_string, module_name=None, add_to_sys_modules=Tr
16
22
  module_name = f"setta_dynamic_module_{uuid.uuid4().hex}"
17
23
 
18
24
  # Add current directory to sys.path if it's not already there
19
- current_dir = CWD
20
- if current_dir not in sys.path:
21
- sys.path.insert(0, current_dir)
25
+ if CWD not in sys.path:
26
+ sys.path.insert(0, CWD)
22
27
 
23
28
  spec = importlib.util.spec_from_loader(module_name, loader=None)
24
29
 
@@ -40,13 +45,23 @@ def import_code_from_string(code_string, module_name=None, add_to_sys_modules=Tr
40
45
 
41
46
 
42
47
  class SettaInMemoryFnSubprocess:
43
- def __init__(self):
48
+ def __init__(self, stop_event, websockets):
44
49
  self.parent_conn, self.child_conn = multiprocessing.Pipe()
45
50
  self.process = multiprocessing.Process(target=self._subprocess_main)
46
51
  self.stdout_parent_conn, self.stdout_child_conn = multiprocessing.Pipe()
47
52
  self.process.daemon = True # Ensure process dies with parent
48
53
  self.process.start()
49
54
 
55
+ self.stop_event = stop_event
56
+ self.websockets = websockets
57
+ self.stdout_queue = queue.Queue()
58
+ self.stdout_processor_task = None
59
+ self.stdout_thread = threading.Thread(target=self.stdout_listener, daemon=True)
60
+ self.stdout_thread.start()
61
+
62
+ if len(self.websockets) > 0:
63
+ self.start_stdout_processor_task()
64
+
50
65
  def _subprocess_main(self):
51
66
  """Main loop in subprocess that handles all requests"""
52
67
  # Initialize store for imported modules
@@ -137,6 +152,10 @@ class SettaInMemoryFnSubprocess:
137
152
  self.stdout_parent_conn.close()
138
153
  self.stdout_child_conn.close()
139
154
 
155
+ self.stdout_thread.join()
156
+ if self.stdout_processor_task:
157
+ self.stdout_processor_task.cancel()
158
+
140
159
  def process_message(self, fn_name, message, cache):
141
160
  if fn_name in cache:
142
161
  exporter_obj = cache[fn_name]
@@ -147,6 +166,51 @@ class SettaInMemoryFnSubprocess:
147
166
  message.content = exporter_obj.output
148
167
  return message.content
149
168
 
169
+ def start_stdout_processor_task(self):
170
+ if self.stdout_processor_task is None or self.stdout_processor_task.done():
171
+ self.stdout_processor_task = asyncio.create_task(
172
+ self.process_stdout_queue()
173
+ )
174
+
175
+ async def stop_stdout_processor_task(self):
176
+ if self.stdout_processor_task and not self.stdout_processor_task.done():
177
+ self.stdout_processor_task.cancel()
178
+ try:
179
+ await self.stdout_processor_task
180
+ except asyncio.CancelledError:
181
+ pass
182
+ self.stdout_processor_task = None
183
+
184
+ async def process_stdout_queue(self):
185
+ while not self.stop_event.is_set():
186
+ try:
187
+ if self.stop_event.is_set():
188
+ break
189
+ if len(self.websockets) > 0:
190
+ stdout_data = self.stdout_queue.get_nowait()
191
+ stdout_data = stdout_data.replace("\n", "\r\n")
192
+ for w in self.websockets:
193
+ await w.send_text(stdout_data)
194
+ self.stdout_queue.task_done()
195
+ except queue.Empty:
196
+ await asyncio.sleep(0.1) # Check for connection every 100ms
197
+ except asyncio.CancelledError:
198
+ break
199
+ except Exception as e:
200
+ if self.stop_event.is_set():
201
+ break
202
+ logger.debug(f"Error processing stdout: {e}")
203
+
204
+ def stdout_listener(self):
205
+ while not self.stop_event.is_set():
206
+ try:
207
+ stdout_data = self.stdout_parent_conn.recv()
208
+ self.stdout_queue.put(stdout_data) # simple put, no async needed
209
+ except Exception as e:
210
+ if self._stop_event.is_set():
211
+ break
212
+ logger.debug(f"Error in stdout listener: {e}")
213
+
150
214
 
151
215
  def add_fns_from_module(fns_dict, module, module_name=None):
152
216
  count = 1
@@ -168,11 +232,11 @@ def add_fns_from_module(fns_dict, module, module_name=None):
168
232
  def get_task_metadata(in_memory_fn, exporter_obj):
169
233
  # None means run the task on every change
170
234
  if in_memory_fn.dependencies is None:
171
- dependencies = None
235
+ dependencies = set([None])
172
236
  # Empty array means only run when the task imported.
173
237
  # Non-empty array means run when specified dependencies update.
174
238
  else:
175
- dependencies = [
239
+ dependencies = set(
176
240
  exporter_obj.var_name_reverse_mapping[d] for d in in_memory_fn.dependencies
177
- ]
178
- return {"dependencies": dependencies}
241
+ )
242
+ return dependencies
@@ -43,7 +43,9 @@ class WebsocketManager:
43
43
  if wid == self.server_cli_id:
44
44
  # process task and send any results back to requester
45
45
  result = await tasks(
46
- message["messageType"], TaskMessage.parse_obj(message)
46
+ message["messageType"],
47
+ TaskMessage.parse_obj(message),
48
+ websocket_manager=self,
47
49
  )
48
50
  if "content" in result:
49
51
  websocket = self.sockets[fromWebsocketId]["websocket"]
@@ -64,10 +66,13 @@ class WebsocketManager:
64
66
  if "location" in message:
65
67
  self.sockets[fromWebsocketId]["location"] = message["location"]
66
68
 
67
- async def send_message_to_requester(self, id, content):
69
+ async def send_message_to_requester(self, id, content, messageType=None):
68
70
  # just send data to target websocket
69
71
  websocket = self.sockets[self.message_id_to_sender_id[id]]["websocket"]
70
- await websocket.send_text(json.dumps({"id": id, "content": content}))
72
+ return_val = {"id": id, "content": content}
73
+ if messageType:
74
+ return_val["messageType"] = messageType
75
+ await websocket.send_text(json.dumps(return_val))
71
76
 
72
77
  async def send_message_to_location(self, content, messageType, location):
73
78
  for w in self.sockets.values():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: setta
3
- Version: 0.0.3.dev3
3
+ Version: 0.0.3.dev5
4
4
  Home-page: https://setta.dev
5
5
  Project-URL: GitHub, https://github.com/settadev/setta
6
6
  License-File: LICENSE
@@ -1,11 +1,11 @@
1
- setta/__init__.py,sha256=aHK3nTsHMoeeQG7I2k8wIkeT23k43hNfu2Y2-cgOh8c,27
1
+ setta/__init__.py,sha256=kH8A5OhSz91E7LZXLnQ3CnbIZBoobjt8lmTWUyCqnuw,27
2
2
  setta/server.py,sha256=P78BMFvcCokVhjnVlNIKcmpCSvmzSqt-33bx4bhOe6Y,4626
3
3
  setta/start.py,sha256=jEeSiocLeBitvg48fa6k1CpLnPI63JHkQ8O-WVM6ch8,3078
4
- setta/cli/__init__.py,sha256=8NFfvFBHtD0oNwSZYPSaHjQTEQxZmCMgCdHtG2Mq160,47
4
+ setta/cli/__init__.py,sha256=UxZG_VOMuF6lEBT3teUgTS9ulsK3wt3Gu3BbAQiAmt8,47
5
5
  setta/cli/connect.py,sha256=Pj2Ten7CQcLQGNnyi5Y-vYslQDN3J8csPcWetlvu_J0,1273
6
6
  setta/cli/logger.py,sha256=M-gGOcYt8Xj7ldNGBAUfA9yL1nX4UpBuQR1lkg_qiSs,6130
7
7
  setta/code_gen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- setta/code_gen/create_runnable_scripts.py,sha256=uZ2l5F0PlldPMD51i0FWiqjLpAMAugrmftKTGaRFjEo,15948
8
+ setta/code_gen/create_runnable_scripts.py,sha256=LXRu8ErO3_e5HCNomnlgfsyxKp2h-Pmm2VFXzBgDDhA,17444
9
9
  setta/code_gen/export_selected.py,sha256=Hpa2uYFxTtxG0R9szY3WQA2Hj6XoejYVT53ET1l7Qmg,26883
10
10
  setta/code_gen/find_placeholders.py,sha256=xWEVVPmyeEhPwoMsCnmMkd-ox3rd50jRur3uxfCqB30,601
11
11
  setta/code_gen/utils.py,sha256=ArBPYA__ekeHjZVUDXanlMEnqCX5-Z_R1rMM-1UbEV0,4088
@@ -87,7 +87,7 @@ setta/routers/artifact.py,sha256=9wHdreg5DsLshhET-6gEDw2Apw_-r8bRF1x3-_dD9mU,266
87
87
  setta/routers/code_info.py,sha256=rDBLkr5VQOlktap3hWA73ls0VrBi5y4mc_SfWzw9ad0,857
88
88
  setta/routers/dependencies.py,sha256=lQDZFcXw-jUXK1q8yglUg3jY9dKoE-xvVcWckKqmOr4,1126
89
89
  setta/routers/in_memory_fn_stdout_websocket.py,sha256=T2BpLzh6PwYQP0qIkFS4r_VfEKBlwl4gkwIaq6r6Phs,604
90
- setta/routers/interactive.py,sha256=WRDG7WHkUMxVddylBhR5v1IU_Qg8vqVIdt2AMkBKCwo,3626
90
+ setta/routers/interactive.py,sha256=juUtPmCyqHSnIb5k6iOYUtfmukp1Z6x25wISlANgUic,4385
91
91
  setta/routers/lsp.py,sha256=DAZqdiRKDWJ9ikjwQetV4_8s9U-EDC91ToJA3u57qnU,385
92
92
  setta/routers/projects.py,sha256=p3zPD3jobYOxBGJSSIYS1Aqu1w-PrJCcEN6dPJ0DT6E,5255
93
93
  setta/routers/reference_renaming.py,sha256=Ec1hz2Nz_hYqk8GyGmUcWKvXo-lVEDbIIK2YbX-wi00,3598
@@ -108,7 +108,7 @@ setta/static/frontend/browserconfig.xml,sha256=w0iw1t89kA7-965LTfyLYrFzewTQnUWE_
108
108
  setta/static/frontend/favicon-16x16.png,sha256=q67Crpy8s3wryu7Y3kffPeysN99Lt4XeFygXhPKize8,740
109
109
  setta/static/frontend/favicon-32x32.png,sha256=4NKXYticYdMrRHmVveHjxqnBU1HWgBT5JyJG8lx3BNE,1027
110
110
  setta/static/frontend/favicon.ico,sha256=02qhEBLsvsgBTZX6dcZElMyivlvrR7Yr6wB8ItEZFsc,15086
111
- setta/static/frontend/index.html,sha256=_bxzxQWKiqvui-oY6epsNEdoYd00oU-Cyi7Ntth1ZMQ,1296
111
+ setta/static/frontend/index.html,sha256=4d4CugkQWpyw6EozUuo1rnSN81dqwLxqea3sWNSeT4w,1296
112
112
  setta/static/frontend/manifest.json,sha256=ULPYw5A68_eNhxuUVXqxT045yhkurKPSz6hjyGcnmhQ,492
113
113
  setta/static/frontend/mstile-144x144.png,sha256=wQqckmRWre2NCCevevI3rv4j0tcduVMkpYr2tPj73cs,2692
114
114
  setta/static/frontend/mstile-150x150.png,sha256=FUwy6PipTofnhmJB5CdXWYgwy-2inq_sIOdOwdDklcY,2674
@@ -184,8 +184,8 @@ setta/static/frontend/assets/cormorant-garamond-latin-700-italic-0bc53e12.woff2,
184
184
  setta/static/frontend/assets/cormorant-garamond-latin-ext-700-italic-525738e0.woff2,sha256=Ulc44CPXdUiI5dY86W76HLk7801Fm9_QywCV-8GRtFU,17240
185
185
  setta/static/frontend/assets/cormorant-garamond-vietnamese-700-italic-99563037.woff2,sha256=mVYwN54qI0RLXqyrDGPUNpBHWSJDKjgUyBRWa2FJ_ao,5248
186
186
  setta/static/frontend/assets/erase-5e0448ea.svg,sha256=XgRI6pChr392LJ-pGbwqqkN8OWcJMEtRGX-Gv-90qjw,872
187
- setta/static/frontend/assets/index-1d4b4ecf.css,sha256=HUtOz9lZUrcZrQMc4nQsS5ixI6ukEUF2qGsCy_F_0DU,232608
188
- setta/static/frontend/assets/index-73adf0a9.js,sha256=VRiK4VG6jp9Z4TKkmNLQaO9WAw_oyj_3MZYA1IwIo7I,2847508
187
+ setta/static/frontend/assets/index-1f218da9.js,sha256=GEYeMbQIVHiDWM2sapWp1VSxuzoVe9sC2IJtNP5021k,2847446
188
+ setta/static/frontend/assets/index-af271c9f.css,sha256=ryccn_uul30_aMdIhgzMlq6GcE0D6x8fyfneCdgaY9o,232608
189
189
  setta/static/frontend/assets/inter-all-400-normal-054f12d0.woff,sha256=BU8S0GmcIMyYte4ESEdQJO-WvL2Rb-38m1n0ujdbYxI,128624
190
190
  setta/static/frontend/assets/inter-all-600-normal-c03769e5.woff,sha256=wDdp5VNyQL_IbxcPThD2qI-ETg_QKj7AmCwMCjqDfLE,139072
191
191
  setta/static/frontend/assets/inter-all-800-normal-15dc6e4b.woff,sha256=FdxuS9xuVumB5nbVcCXyt3IWqzS4Z75qiRz_0FV5al0,139120
@@ -232,8 +232,8 @@ setta/static/seed/.DS_Store,sha256=ENxJvDQd7Te_U8gExcXtHE-mAeBUYOHELRfDWgN1NmA,6
232
232
  setta/static/seed/examples/.DS_Store,sha256=1lFlJ5EFymdzGAUAaI30vcaaLHt3F1LwpG7xILf9jsM,6148
233
233
  setta/tasks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
234
234
  setta/tasks/task_runner.py,sha256=gMXpfZWFMQbix2MfrHVCKB7BxQCjO8JH2P8cxUmt1ms,849
235
- setta/tasks/tasks.py,sha256=ImZ6cSQj4HBDP41V9Uf3elxm9JSYxRONu8iSvYzwlOw,5910
236
- setta/tasks/utils.py,sha256=4yZkDa6vmeYncejCN_o4afBb7uJ8Sn5X4svdQOFrw0g,6126
235
+ setta/tasks/tasks.py,sha256=dR02kybZnwiGKt3YhlfWgx0fDUPCoDeslrnm8mJcr74,5956
236
+ setta/tasks/utils.py,sha256=D_M5rZRu0N4z21mM2jyrKBSUCCFT6LrQgegr3uf1NgM,8545
237
237
  setta/tasks/fns/__init__.py,sha256=JhGzzQGaT9BWtF3pOmguh6pzIF9kdG3jdDNLyYZ2w7g,461
238
238
  setta/tasks/fns/codeAreaAutocomplete.py,sha256=gJ5JbjkWDyTothr-UF-YlOxrbVzj2iyOVK7XD3lfhSQ,6416
239
239
  setta/tasks/fns/codeAreaFindTemplateVars.py,sha256=vD9rY8VNPavv6VKa1bnxRPPRDNvFQy6mPIZRl-_3GnY,3708
@@ -253,10 +253,10 @@ setta/utils/generate_memorable_string.py,sha256=ZIn8gQm3cpMuqTCRgAPXAm5VdbWW7O3f
253
253
  setta/utils/generate_new_filename.py,sha256=KBLX6paDmTvXR-027TpqQkfijIXc7mCfhen-u1WZARA,3067
254
254
  setta/utils/section_contents.py,sha256=V2HQPik6DfSXw4j7IalbP5AZ3OEGCbtL5ub3xL-Q_Qo,4141
255
255
  setta/utils/utils.py,sha256=KjzcvgM3Ab3IcE8vaWYtgBpwzPLKg0LmblnHLoYZJHM,9164
256
- setta/utils/websocket_manager.py,sha256=5k_GkOSKT9e40fiu6-PpkRrrlr3LOlqDshF73jdpwlg,3581
257
- setta-0.0.3.dev3.dist-info/LICENSE,sha256=us9fuCq9wmiZVzayjKxNZ2iJYF6dROe0Qp57ToCO7XU,11361
258
- setta-0.0.3.dev3.dist-info/METADATA,sha256=OlP6-QgmDne-62YAol-nXurqCByDSoZYscT_8y3ahc0,829
259
- setta-0.0.3.dev3.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
260
- setta-0.0.3.dev3.dist-info/entry_points.txt,sha256=P0qCESy9fWF2q1EQ9JufGldCSnPHplDPn8J6Bgk5hB0,42
261
- setta-0.0.3.dev3.dist-info/top_level.txt,sha256=8G4lmRzVOnJ11_DescPVHE6MQZH-o06A0nGsDDV2ngY,6
262
- setta-0.0.3.dev3.dist-info/RECORD,,
256
+ setta/utils/websocket_manager.py,sha256=S2lEGZsc2OhW0yKLW9VEcH7wi7ppzTfDMQa_hxf3ovc,3772
257
+ setta-0.0.3.dev5.dist-info/LICENSE,sha256=us9fuCq9wmiZVzayjKxNZ2iJYF6dROe0Qp57ToCO7XU,11361
258
+ setta-0.0.3.dev5.dist-info/METADATA,sha256=IWvmVuV-CtMykwttA1EMFK8RuFQEbFMBfVS3gvL5SIs,829
259
+ setta-0.0.3.dev5.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
260
+ setta-0.0.3.dev5.dist-info/entry_points.txt,sha256=P0qCESy9fWF2q1EQ9JufGldCSnPHplDPn8J6Bgk5hB0,42
261
+ setta-0.0.3.dev5.dist-info/top_level.txt,sha256=8G4lmRzVOnJ11_DescPVHE6MQZH-o06A0nGsDDV2ngY,6
262
+ setta-0.0.3.dev5.dist-info/RECORD,,