61 Resolve the given path to an absolute path,
62 expanding environment variables.
63 If path looks relative and does not point to anything
66 if isinstance(path, Path):
68 path = os.path.expandvars(path)
73 path, suffix = path.rsplit(
":", 1)
76 if not os.path.isabs(path):
77 base_dir = file_path_for_class(cls).parent
78 possible_path = str((base_dir / path).resolve())
79 if os.path.exists(possible_path):
136 Collect stack trace from a running process using the available debugger.
137 Uses lldb on macOS and gdb on Linux. Returns a message if no debugger
142 if sys.platform ==
"darwin":
144 if not shutil.which(
"lldb"):
145 return "(lldb not available for stack trace collection)"
157 if not shutil.which(
"gdb"):
158 return "(gdb not available for stack trace collection)"
164 "--eval-command=thread apply all backtrace",
166 debugger = subprocess.Popen(
167 cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
169 return debugger.communicate()[0].decode(
"utf-8", errors=
"backslashreplace")
188 Run the specified program and capture its output.
190 start_time = datetime.now()
193 proc = subprocess.Popen(
195 stdout=subprocess.PIPE,
196 stderr=subprocess.PIPE,
201 stdout_chunks, stderr_chunks = [], []
203 exceeded_stream = stack_trace = run_exception =
None
205 proc.stdout.fileno(): (stdout_chunks,
"stdout"),
206 proc.stderr.fileno(): (stderr_chunks,
"stderr"),
210 nonlocal stdout, stderr, exceeded_stream
211 open_streams = dict(streams)
212 while open_streams
and not exceeded_stream:
216 exited = proc.poll()
is not None
217 readable, _, _ = select.select(
218 open_streams.keys(), [], [], 0
if exited
else cls.
timeout
220 if exited
and not readable:
222 for fileno
in readable:
223 data = os.read(fileno, 65536)
225 del open_streams[fileno]
227 chunks, stream_name = streams[fileno]
229 if sum(len(chunk)
for chunk
in chunks) > STDOUT_LIMIT:
230 exceeded_stream = stream_name
233 if not exceeded_stream:
235 stdout = b
"".join(stdout_chunks)
236 stderr = b
"".join(stderr_chunks)
238 thread = threading.Thread(target=read_output)
242 if thread.is_alive():
245 elif exceeded_stream:
247 "Stream exceeded size limit", exceeded_stream
250 end_time = datetime.now()
252 completed_process = subprocess.CompletedProcess(
254 returncode=proc.returncode,
265 env_to_record.extend(
266 env[name]
for name
in env
if re.match(
r"GAUDI_ENV_TO_RECORD(_\d+)?", name)
270 for key, value
in env.items()
271 if any(re.match(exp, key)
for exp
in env_to_record)
274 completed_process=completed_process,
275 start_time=start_time,
277 run_exception=run_exception,
279 expanded_command=command,
299 record_property: Callable[[str, str],
None],
300 fixture_result: FixtureResult,
301 reference_path: Path |
None,
304 Record properties and handle any failures during fixture setup.
306 for key, value
in fixture_result.to_dict().items():
307 if value
is not None:
308 record_property(key, value)
310 record_property(
"reference_file", str(reference_path))
312 if fixture_result.run_exception:
313 pytest.fail(f
"{fixture_result.run_exception}")