Files
Kay Hayen 04281e34ef Tests: Allow system package file accesses for Debian Python flavor
When the Python flavor is "Debian Python", the test file access checker
now tolerates loaded files under system library paths (/usr/lib, /lib,
/usr/lib64, /lib64) since Debian's Python relies on system-packaged libraries.
2026-05-26 13:30:45 +02:00

209 lines
6.4 KiB
Python
Executable File

#!/usr/bin/env python
# Copyright 2026, Kay Hayen, mailto:kay.hayen@gmail.com find license text at end of file
"""Runner for onefile program tests of Nuitka.
These tests aim at showing that one specific functions work in onefile
mode, trying to find issues with that form of packaging.
"""
import os
import sys
# Find nuitka package relative to us. The replacement is for POSIX python
# and Windows paths on command line.
sys.path.insert(
0,
os.path.normpath(
os.path.join(
os.path.dirname(os.path.abspath(__file__.replace("\\", os.sep))), "..", ".."
)
),
)
# isort:start
from nuitka.reports.CompilationReportReader import (
getCompilationOutputBinary,
getCompilationPythonFlavor,
parseCompilationReport,
)
from nuitka.tools.testing.Common import (
checkLoadedFileAccesses,
checkTestRequirements,
compareWithCPython,
createSearchMode,
displayFileContents,
displayRuntimeTraces,
getTempDir,
reportSkip,
scanDirectoryForTestCases,
setup,
test_logger,
)
from nuitka.tools.testing.RuntimeTracing import (
doesSupportTakingRuntimeTrace,
getRuntimeTraceOfLoadedFiles,
)
from nuitka.utils.FileOperations import deleteFile
from nuitka.utils.Timing import TimerReport
def displayError(dirname, filename):
assert dirname is None
inclusion_log_path = filename[:-3] + ".py.inclusion.log"
displayFileContents("inclusion log", inclusion_log_path)
def main():
python_version = setup(suite="onefile", needs_io_encoding=True)
search_mode = createSearchMode()
for filename in scanDirectoryForTestCases("."):
active = search_mode.consider(dirname=None, filename=filename)
if not active:
continue
report_filename = "test-compilation-report.xml"
extra_flags = [
"expect_success",
"remove_output",
# Keep the binary, normally "remove_output" includes that.
"--keep-binary",
# Cache the CPython results for reuse, they will normally not change.
"cpython_cache",
# To understand what is slow.
"timing",
# The onefile can warn about zstandard not being installed.
"ignore_warnings",
# To be able to find where the binary ended up being created.
"--report=%s" % report_filename,
]
if filename == "KeyboardInterruptTest.py":
if python_version < (3,):
reportSkip(
"Python2 reports KeyboardInterrupt, but too late",
".",
filename,
)
continue
if os.name == "nt":
reportSkip(
"Testing cannot send KeyboardInterrupt on Windows yet",
".",
filename,
)
continue
extra_flags.append("--send-ctrl-c")
if filename == "ExternalDataTest.py":
extra_flags.append("--output-dir=%s" % getTempDir())
# skip each test if their respective requirements are not met
requirements_met, error_message = checkTestRequirements(filename)
if not requirements_met:
reportSkip(error_message, ".", filename)
continue
test_logger.info(
"Consider output of onefile mode compiled program: %s" % filename
)
# First compare so we know the program behaves identical.
compareWithCPython(
dirname=None,
filename=filename,
extra_flags=extra_flags,
search_mode=search_mode,
on_error=displayError,
)
compilation_report = parseCompilationReport(report_filename)
binary_filename = getCompilationOutputBinary(
compilation_report=compilation_report,
prefixes=(
(
"~",
os.path.expanduser("~"),
),
(
"${cwd}",
os.getcwd(),
),
),
)
try:
if not doesSupportTakingRuntimeTrace():
test_logger.info("Runtime traces are not possible on this machine.")
continue
# This test case requires a kill, so kill it there.
if filename == "KeyboardInterruptTest.py":
test_logger.info(
"Runtime traces are not taken for case that needs killing."
)
continue
# Then use "strace" on the result.
with TimerReport(
"Determining run time loaded files took %.2f", logger=test_logger
):
loaded_filenames = getRuntimeTraceOfLoadedFiles(
logger=test_logger, command=[binary_filename]
)
illegal_accesses = checkLoadedFileAccesses(
loaded_filenames=loaded_filenames,
current_dir=os.getcwd(),
python_flavor=getCompilationPythonFlavor(
compilation_report=compilation_report
),
)
if illegal_accesses:
displayError(None, filename)
displayRuntimeTraces(test_logger, binary_filename)
test_logger.warning(
"Should not access these file(s): '%s'."
% ",".join(illegal_accesses)
)
search_mode.onErrorDetected(1)
finally:
deleteFile(binary_filename, must_exist=True)
search_mode.finish()
if __name__ == "__main__":
main()
# Python test originally created or extracted from other peoples work. The
# parts from me are licensed as below. It is at least Free Software where
# it's copied from other people. In these cases, that will normally be
# indicated.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.