@@ -154,40 +154,17 @@ def run(self, project_root: str) -> L2Result:
154154 logger .debug ("L2: pytest not available" )
155155 return L2Result (passed = True , tests_passed = 0 , tests_total = 0 )
156156
157- # Run pytest
158- env = os .environ .copy ()
159- # Add project_root to PYTHONPATH so test imports work
160- existing_pythonpath = env .get ("PYTHONPATH" , "" )
161- if existing_pythonpath :
162- env ["PYTHONPATH" ] = f"{ root } { os .pathsep } { existing_pythonpath } "
163- else :
164- env ["PYTHONPATH" ] = str (root )
165-
166- try :
167- proc = subprocess .run (
168- [sys .executable , "-m" , "pytest" , "tests/" , "--tb=short" , "-q" ],
169- cwd = root ,
170- capture_output = True ,
171- timeout = self .TIMEOUT ,
172- text = True ,
173- env = env ,
174- )
175- except subprocess .TimeoutExpired :
176- return L2Result (
177- passed = False ,
178- error_type = "TEST_FAILURE" ,
179- error_detail = "pytest timed out after 60s" ,
180- )
157+ # Run pytest — prefer Docker sandbox, fall back to local
158+ pytest_cmd = f"{ sys .executable } -m pytest tests/ --tb=short -q"
159+ stdout , stderr , rc = self ._run_in_sandbox (root , pytest_cmd )
181160
182- combined = proc . stdout + "\n " + proc . stderr
161+ combined = stdout + "\n " + stderr
183162 passed , total = self ._parse_counts (combined )
184163
185- if proc . returncode == 0 :
164+ if rc == 0 :
186165 return L2Result (passed = True , tests_passed = passed , tests_total = total )
187166
188- # Failure — classify
189167 error_type , error_detail = classify_error (combined )
190-
191168 return L2Result (
192169 passed = False ,
193170 tests_passed = passed ,
@@ -196,6 +173,32 @@ def run(self, project_root: str) -> L2Result:
196173 error_detail = error_detail ,
197174 )
198175
176+ @staticmethod
177+ def _run_in_sandbox (root , command : str ) -> tuple :
178+ """Run command in Docker sandbox if available, otherwise locally."""
179+ try :
180+ from core .docker_sandbox import DockerSandbox
181+ sandbox = DockerSandbox ()
182+ if sandbox .is_available ():
183+ logger .info ("[L2] Running in Docker sandbox" )
184+ return sandbox .run_command (command = command , workspace = str (root ))
185+ except Exception as e :
186+ logger .debug ("[L2] Docker sandbox unavailable: %s" , e )
187+
188+ # Local fallback
189+ env = os .environ .copy ()
190+ existing = env .get ("PYTHONPATH" , "" )
191+ env ["PYTHONPATH" ] = f"{ root } { os .pathsep } { existing } " if existing else str (root )
192+ try :
193+ proc = subprocess .run (
194+ command .split (),
195+ cwd = root , capture_output = True , text = True , timeout = 120 ,
196+ env = env ,
197+ )
198+ return proc .stdout , proc .stderr , proc .returncode
199+ except subprocess .TimeoutExpired :
200+ return "" , "pytest timed out after 120s" , - 1
201+
199202 @staticmethod
200203 def _parse_counts (output : str ) -> tuple [int , int ]:
201204 """Extract passed/total test counts from pytest output."""
0 commit comments