@@ -114,6 +114,65 @@ def _get_execute_request(
114114 }
115115 )
116116
117+ def _get_env_var_command (self , key : str , value : str , action : str = "set" ) -> str :
118+ """Get environment variable command for the current language."""
119+ if action == "set" :
120+ if self .language == "python" :
121+ return f"import os; os.environ['{ key } '] = '{ value } '"
122+ elif self .language in ["javascript" , "typescript" ]:
123+ return f"process.env['{ key } '] = '{ value } '"
124+ elif self .language == "deno" :
125+ return f"Deno.env.set('{ key } ', '{ value } ')"
126+ elif self .language == "r" :
127+ return f'Sys.setenv({ key } = "{ value } ")'
128+ elif self .language == "java" :
129+ return f'System.setProperty("{ key } ", "{ value } ");'
130+ elif self .language == "bash" :
131+ return f"export { key } ='{ value } '"
132+ elif action == "delete" :
133+ if self .language == "python" :
134+ return f"import os; del os.environ['{ key } ']"
135+ elif self .language in ["javascript" , "typescript" ]:
136+ return f"delete process.env['{ key } ']"
137+ elif self .language == "deno" :
138+ return f"Deno.env.delete('{ key } ')"
139+ elif self .language == "r" :
140+ return f"Sys.unsetenv('{ key } ')"
141+ elif self .language == "java" :
142+ return f'System.clearProperty("{ key } ");'
143+ elif self .language == "bash" :
144+ return f"unset { key } "
145+ return ""
146+
147+ def _build_env_vars_code (self , env_vars : Dict [StrictStr , str ]) -> str :
148+ """Build environment variable code for the current language."""
149+ env_commands = []
150+ for k , v in env_vars .items ():
151+ command = self ._get_env_var_command (k , v , "set" )
152+ if command :
153+ env_commands .append (command )
154+
155+ return "\n " .join (env_commands )
156+
157+ def _build_env_vars_cleanup_code (self , env_vars : Dict [StrictStr , str ]) -> str :
158+ """Build environment variable cleanup code for the current language."""
159+ cleanup_commands = []
160+
161+ for key in env_vars :
162+ # Check if this var exists in global env vars
163+ if self .global_env_vars and key in self .global_env_vars :
164+ # Reset to global value
165+ value = self .global_env_vars [key ]
166+ command = self ._get_env_var_command (key , value , "set" )
167+ else :
168+ # Remove the variable
169+ command = self ._get_env_var_command (key , "" , "delete" )
170+
171+ if command :
172+ cleanup_commands .append (command )
173+
174+ return "\n " .join (cleanup_commands )
175+
117176 async def _wait_for_result (self , message_id : str ):
118177 queue = self ._executions [message_id ].queue
119178
@@ -133,84 +192,6 @@ async def _wait_for_result(self, message_id: str):
133192
134193 yield output .model_dump (exclude_none = True )
135194
136- async def set_env_vars (self , env_vars : Dict [StrictStr , str ]):
137- message_id = str (uuid .uuid4 ())
138- self ._executions [message_id ] = Execution (in_background = True )
139-
140- env_commands = []
141- for k , v in env_vars .items ():
142- if self .language == "python" :
143- env_commands .append (f"import os; os.environ['{ k } '] = '{ v } '" )
144- elif self .language in ["javascript" , "typescript" ]:
145- env_commands .append (f"process.env['{ k } '] = '{ v } '" )
146- elif self .language == "deno" :
147- env_commands .append (f"Deno.env.set('{ k } ', '{ v } ')" )
148- elif self .language == "r" :
149- env_commands .append (f'Sys.setenv({ k } = "{ v } ")' )
150- elif self .language == "java" :
151- env_commands .append (f'System.setProperty("{ k } ", "{ v } ");' )
152- elif self .language == "bash" :
153- env_commands .append (f"export { k } ='{ v } '" )
154- else :
155- return
156-
157- if env_commands :
158- env_vars_snippet = "\n " .join (env_commands )
159- logger .info (f"Setting env vars: { env_vars_snippet } for { self .language } " )
160- request = self ._get_execute_request (message_id , env_vars_snippet , True )
161- await self ._ws .send (request )
162-
163- async for item in self ._wait_for_result (message_id ):
164- if item ["type" ] == "error" :
165- raise ExecutionError (f"Error during execution: { item } " )
166-
167- async def reset_env_vars (self , env_vars : Dict [StrictStr , str ]):
168- # Create a dict of vars to reset and a list of vars to remove
169- vars_to_reset = {}
170- vars_to_remove = []
171-
172- for key in env_vars :
173- if self .global_env_vars and key in self .global_env_vars :
174- vars_to_reset [key ] = self .global_env_vars [key ]
175- else :
176- vars_to_remove .append (key )
177-
178- # Reset vars that exist in global env vars
179- if vars_to_reset :
180- await self .set_env_vars (vars_to_reset )
181-
182- # Remove vars that don't exist in global env vars
183- if vars_to_remove :
184- message_id = str (uuid .uuid4 ())
185- self ._executions [message_id ] = Execution (in_background = True )
186-
187- remove_commands = []
188- for key in vars_to_remove :
189- if self .language == "python" :
190- remove_commands .append (f"import os; del os.environ['{ key } ']" )
191- elif self .language in ["javascript" , "typescript" ]:
192- remove_commands .append (f"delete process.env['{ key } ']" )
193- elif self .language == "deno" :
194- remove_commands .append (f"Deno.env.delete('{ key } ')" )
195- elif self .language == "r" :
196- remove_commands .append (f"Sys.unsetenv('{ key } ')" )
197- elif self .language == "java" :
198- remove_commands .append (f'System.clearProperty("{ key } ");' )
199- elif self .language == "bash" :
200- remove_commands .append (f"unset { key } " )
201- else :
202- return
203-
204- if remove_commands :
205- remove_snippet = "\n " .join (remove_commands )
206- logger .info (f"Removing env vars: { remove_snippet } for { self .language } " )
207- request = self ._get_execute_request (message_id , remove_snippet , True )
208- await self ._ws .send (request )
209-
210- async for item in self ._wait_for_result (message_id ):
211- if item ["type" ] == "error" :
212- raise ExecutionError (f"Error during execution: { item } " )
213-
214195 async def change_current_directory (
215196 self , path : Union [str , StrictStr ], language : str
216197 ):
@@ -256,12 +237,22 @@ async def execute(
256237 raise Exception ("WebSocket not connected" )
257238
258239 async with self ._lock :
259- # set env vars (will override global env vars)
240+ # Build the complete code snippet with env vars
241+ complete_code = code
242+
260243 if env_vars :
261- await self .set_env_vars (env_vars )
262-
263- logger .info (code )
264- request = self ._get_execute_request (message_id , code , False )
244+ # Add env var setup at the beginning
245+ env_setup_code = self ._build_env_vars_code (env_vars )
246+ if env_setup_code :
247+ complete_code = f"{ env_setup_code } \n { complete_code } "
248+
249+ # Add env var cleanup at the end
250+ env_cleanup_code = self ._build_env_vars_cleanup_code (env_vars )
251+ if env_cleanup_code :
252+ complete_code = f"{ complete_code } \n { env_cleanup_code } "
253+
254+ logger .info (f"Executing complete code: { complete_code } " )
255+ request = self ._get_execute_request (message_id , complete_code , False )
265256
266257 # Send the code for execution
267258 await self ._ws .send (request )
@@ -272,10 +263,6 @@ async def execute(
272263
273264 del self ._executions [message_id ]
274265
275- # reset env vars to their previous values, if they were set globally or remove them
276- if env_vars :
277- await self .reset_env_vars (env_vars )
278-
279266 async def _receive_message (self ):
280267 if not self ._ws :
281268 logger .error ("No WebSocket connection" )
0 commit comments