setta 0.0.14.dev4__py3-none-any.whl → 0.0.14.dev6__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 CHANGED
@@ -1 +1 @@
1
- __version__ = "0.0.14.dev4"
1
+ __version__ = "0.0.14.dev6"
@@ -1,8 +1,12 @@
1
1
  import asyncio
2
2
  import inspect
3
+ import logging
4
+ import traceback
3
5
  from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
4
6
  from enum import Enum
5
7
 
8
+ logger = logging.getLogger(__name__)
9
+
6
10
 
7
11
  class RunType(Enum):
8
12
  SUBPROCESS = "SUBPROCESS"
@@ -16,14 +20,22 @@ class TaskRunner:
16
20
  self.process_executor = ProcessPoolExecutor(max_workers=2)
17
21
 
18
22
  async def run(self, fn, fn_args, run_as):
19
- if inspect.iscoroutinefunction(fn):
20
- return await fn(*fn_args)
23
+ logger.debug(f"TaskRunner running function {fn.__name__} with run_as={run_as}")
24
+ try:
25
+ if inspect.iscoroutinefunction(fn):
26
+ return await fn(*fn_args)
21
27
 
22
- if run_as == RunType.NONE:
23
- return fn(*fn_args)
24
- elif run_as == RunType.THREAD:
25
- executor = self.thread_executor
26
- elif run_as == RunType.SUBPROCESS:
27
- executor = self.process_executor
28
+ if run_as == RunType.NONE:
29
+ return fn(*fn_args)
30
+ elif run_as == RunType.THREAD:
31
+ executor = self.thread_executor
32
+ elif run_as == RunType.SUBPROCESS:
33
+ executor = self.process_executor
28
34
 
29
- return await asyncio.get_running_loop().run_in_executor(executor, fn, *fn_args)
35
+ return await asyncio.get_running_loop().run_in_executor(
36
+ executor, fn, *fn_args
37
+ )
38
+ except Exception as e:
39
+ logger.error(f"Error in TaskRunner.run: {str(e)}")
40
+ traceback.print_exc()
41
+ raise
setta/tasks/tasks.py CHANGED
@@ -3,6 +3,7 @@ import copy
3
3
  import json
4
4
  import logging
5
5
  import time
6
+ import traceback
6
7
  from typing import Dict
7
8
 
8
9
  from setta.database.utils import create_new_id
@@ -87,15 +88,25 @@ class Tasks:
87
88
  or None in fnInfo["dependencies"]
88
89
  or any(k in fnInfo["dependencies"] for k in message.content.keys())
89
90
  ):
90
- # Send message to subprocess
91
- sp_info["subprocess"].parent_conn.send(
92
- {
93
- "type": call_type,
94
- "fn_name": fn_name,
95
- "message": message,
96
- "other_data": other_data,
97
- }
91
+ logger.debug(
92
+ f"Sending message to subprocess {sp_key}, function {fn_name}, message type: {call_type}"
98
93
  )
94
+ try:
95
+ # Send message to subprocess
96
+ sp_info["subprocess"].parent_conn.send(
97
+ {
98
+ "type": call_type,
99
+ "fn_name": fn_name,
100
+ "message": message,
101
+ "other_data": other_data,
102
+ }
103
+ )
104
+ except Exception as e:
105
+ logger.error(
106
+ f"Error sending message to subprocess {sp_key}: {str(e)}"
107
+ )
108
+ traceback.print_exc()
109
+ continue # Skip to next function if we can't send
99
110
 
100
111
  # Create task for receiving response
101
112
  task = asyncio.create_task(
@@ -127,23 +138,43 @@ class Tasks:
127
138
  self, subprocess_key, fn_name, msg_id, recv_fn, websocket_manager, results
128
139
  ):
129
140
  # Run the receive function in a thread
141
+ logger.debug(
142
+ f"Waiting for response from subprocess {subprocess_key}, function {fn_name}"
143
+ )
130
144
  start_time = time.perf_counter()
131
- result = await self.task_runner.run(recv_fn, [], RunType.THREAD)
132
- elapsed_time = time.perf_counter() - start_time
133
- if result["status"] == "success":
134
- self.update_average_subprocess_fn_time(
135
- subprocess_key, fn_name, elapsed_time
145
+ try:
146
+ result = await self.task_runner.run(recv_fn, [], RunType.THREAD)
147
+ logger.debug(
148
+ f"Received response from subprocess {subprocess_key}, function {fn_name}: status={result.get('status', 'unknown')}"
136
149
  )
137
- if websocket_manager is not None:
138
- if result["content"]:
139
- await websocket_manager.send_message_to_requester(
140
- msg_id, result["content"], result["messageType"]
141
- )
142
- await self.maybe_send_latest_run_time_info(
143
- subprocess_key, fn_name, msg_id, websocket_manager
150
+
151
+ elapsed_time = time.perf_counter() - start_time
152
+ if result["status"] == "success":
153
+ self.update_average_subprocess_fn_time(
154
+ subprocess_key, fn_name, elapsed_time
144
155
  )
145
- else:
146
- results.append(result)
156
+ if websocket_manager is not None:
157
+ if result["content"]:
158
+ await websocket_manager.send_message_to_requester(
159
+ msg_id, result["content"], result["messageType"]
160
+ )
161
+ await self.maybe_send_latest_run_time_info(
162
+ subprocess_key, fn_name, msg_id, websocket_manager
163
+ )
164
+ else:
165
+ results.append(result)
166
+ except EOFError:
167
+ logger.error(
168
+ f"EOF error when receiving response from subprocess {subprocess_key}, function {fn_name}"
169
+ )
170
+ # Add stack trace to see where exactly the error occurs
171
+ traceback.print_exc()
172
+ # Consider adding a placeholder result or raising to caller
173
+ except Exception as e:
174
+ logger.error(
175
+ f"Error receiving response from subprocess {subprocess_key}, function {fn_name}: {str(e)}"
176
+ )
177
+ traceback.print_exc()
147
178
 
148
179
  async def add_custom_fns(self, code_graph, exporter_obj):
149
180
  for c in code_graph:
setta/tasks/utils.py CHANGED
@@ -61,8 +61,17 @@ class SettaInMemoryFnSubprocess:
61
61
  sys.stderr = output_capture
62
62
 
63
63
  while True:
64
- msg = self.child_conn.recv() # Wait for requests
65
- msg_type = msg["type"]
64
+ try:
65
+ msg = self.child_conn.recv()
66
+ msg_type = msg["type"]
67
+ logger.debug(f"Subprocess received message type: {msg_type}")
68
+ except EOFError:
69
+ logger.error("EOF error when receiving message in subprocess")
70
+ break
71
+ except Exception as e:
72
+ logger.error(f"Error receiving message in subprocess: {str(e)}")
73
+ traceback.print_exc()
74
+ break
66
75
 
67
76
  if msg_type == "shutdown":
68
77
  # Signal all worker threads to stop
@@ -114,21 +123,43 @@ class SettaInMemoryFnSubprocess:
114
123
 
115
124
  elif msg_type == "call" or msg_type == "call_with_new_exporter_obj":
116
125
  fn_name = msg["fn_name"]
126
+ try:
127
+ logger.debug(
128
+ f"Subprocess about to process message for {fn_name}"
129
+ )
130
+ # Start a worker for this function if needed
131
+ self._start_worker_for_fn(
132
+ fn_name,
133
+ fn_workers,
134
+ fn_message_queues,
135
+ fns_dict,
136
+ cache,
137
+ lock,
138
+ send_lock,
139
+ self.child_conn,
140
+ )
117
141
 
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,
128
- )
129
-
130
- # Add the message to the function's queue
131
- fn_message_queues[fn_name].put(msg)
142
+ # Add the message to the function's queue
143
+ fn_message_queues[fn_name].put(msg)
144
+ except Exception as e:
145
+ logger.error(
146
+ f"Error processing message for {fn_name}: {str(e)}"
147
+ )
148
+ traceback.print_exc()
149
+ # Make sure to send an error response, so the parent doesn't hang
150
+ with send_lock:
151
+ try:
152
+ self.child_conn.send(
153
+ {
154
+ "status": "error",
155
+ "error": str(e),
156
+ "messageType": None,
157
+ }
158
+ )
159
+ except:
160
+ logger.error(
161
+ "Failed to send error response back to parent"
162
+ )
132
163
 
133
164
  except Exception as e:
134
165
  traceback.print_exc()
@@ -145,11 +176,14 @@ class SettaInMemoryFnSubprocess:
145
176
  self, fn_name, fn_message_queues, fns_dict, cache, lock, send_lock, child_conn
146
177
  ):
147
178
  """Worker thread that processes messages for a specific function"""
179
+ logger.debug(f"Started worker thread for {fn_name}")
148
180
  while True:
149
181
  try:
150
182
  # Get a message from the queue
151
183
  msg = fn_message_queues[fn_name].get()
152
-
184
+ logger.debug(
185
+ f"Worker thread for {fn_name} got message of type: {msg.get('type') if msg else 'None'}"
186
+ )
153
187
  if msg is None: # Sentinel value to stop the thread
154
188
  break
155
189
 
@@ -241,10 +275,11 @@ class SettaInMemoryFnSubprocess:
241
275
 
242
276
  # Send shutdown message to the subprocess
243
277
  try:
278
+ logger.debug("Sending shutdown message to subprocess")
244
279
  self.parent_conn.send({"type": "shutdown"})
245
- except (BrokenPipeError, EOFError):
246
- # Pipe might already be closed, that's okay
247
- pass
280
+ logger.debug("Shutdown message sent")
281
+ except (BrokenPipeError, EOFError) as e:
282
+ logger.error(f"Error sending shutdown message: {str(e)}")
248
283
 
249
284
  # Join the process with timeout
250
285
  self.process.join(timeout=2)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: setta
3
- Version: 0.0.14.dev4
3
+ Version: 0.0.14.dev6
4
4
  Summary: Python without the donkeywork.
5
5
  Home-page: https://setta.dev
6
6
  Author: Kevin Musgrave, Jeff Musgrave
@@ -1,4 +1,4 @@
1
- setta/__init__.py,sha256=9veran4Ad41E_iJ8FcUXuAdGf6tKlQnmP63HirwZdO8,28
1
+ setta/__init__.py,sha256=Au0i6BplPktnDDP961GPD0r_9xhbmzMtWXB1881eIRw,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
@@ -229,9 +229,9 @@ setta/static/frontend/assets/logo/logo.svg,sha256=k3XeAlA6hEaNfjnXG05hyb-8u1p_Fr
229
229
  setta/static/seed/.DS_Store,sha256=ENxJvDQd7Te_U8gExcXtHE-mAeBUYOHELRfDWgN1NmA,6148
230
230
  setta/static/seed/examples/.DS_Store,sha256=1lFlJ5EFymdzGAUAaI30vcaaLHt3F1LwpG7xILf9jsM,6148
231
231
  setta/tasks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
232
- setta/tasks/task_runner.py,sha256=gMXpfZWFMQbix2MfrHVCKB7BxQCjO8JH2P8cxUmt1ms,849
233
- setta/tasks/tasks.py,sha256=uG-S3jN9qZEolHtXkJZ4LMi-8LrNPctQR6TVWPlyeTs,10206
234
- setta/tasks/utils.py,sha256=cTmHJGPk6HHbl7nNTPV2KaTugkdSRJTow0z4A05b0lg,15901
232
+ setta/tasks/task_runner.py,sha256=2bykjmSDPZ6lFqeaKTFYPN1eqHtrKDIZJpIi4PztL9Q,1232
233
+ setta/tasks/tasks.py,sha256=o8YVQvEW3uzhMTF38HFk_IgHVe4Wyye7ybb7QZm_-TQ,11695
234
+ setta/tasks/utils.py,sha256=GnFnNVhvXxzoIZtsvhDip12BMKVd73S3UCHdm7ZP01s,17786
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.dev4.dist-info/LICENSE,sha256=us9fuCq9wmiZVzayjKxNZ2iJYF6dROe0Qp57ToCO7XU,11361
256
- setta-0.0.14.dev4.dist-info/METADATA,sha256=JUVKYWOIw0XU77QDXfJhbcNVN9N5xkrirMToSOucr0Y,7517
257
- setta-0.0.14.dev4.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
258
- setta-0.0.14.dev4.dist-info/entry_points.txt,sha256=P0qCESy9fWF2q1EQ9JufGldCSnPHplDPn8J6Bgk5hB0,42
259
- setta-0.0.14.dev4.dist-info/top_level.txt,sha256=8G4lmRzVOnJ11_DescPVHE6MQZH-o06A0nGsDDV2ngY,6
260
- setta-0.0.14.dev4.dist-info/RECORD,,
255
+ setta-0.0.14.dev6.dist-info/LICENSE,sha256=us9fuCq9wmiZVzayjKxNZ2iJYF6dROe0Qp57ToCO7XU,11361
256
+ setta-0.0.14.dev6.dist-info/METADATA,sha256=UZ7Aa4y8MuovjaCfTVklgMKW9gokelnp1mWFNeLKba8,7517
257
+ setta-0.0.14.dev6.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
258
+ setta-0.0.14.dev6.dist-info/entry_points.txt,sha256=P0qCESy9fWF2q1EQ9JufGldCSnPHplDPn8J6Bgk5hB0,42
259
+ setta-0.0.14.dev6.dist-info/top_level.txt,sha256=8G4lmRzVOnJ11_DescPVHE6MQZH-o06A0nGsDDV2ngY,6
260
+ setta-0.0.14.dev6.dist-info/RECORD,,