tests: move and reorganize couple more tests from test_libraries.py #1442
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: CI | |
# Controls when the action will run. Triggers the workflow on push or pull request | |
# events for develop and v4 branche. | |
on: | |
push: | |
branches: | |
- 'develop' | |
- 'v4' | |
- 'tests-cleanup' | |
pull_request: | |
branches: | |
- '**' | |
- '!master' | |
- '!pyup/**' | |
env: | |
# Colored pytest output on CI despite not having a tty | |
FORCE_COLOR: 1 | |
# Enable strict unpack mode to catch file duplication problems in onefile builds (at executable run-time). | |
PYINSTALLER_STRICT_UNPACK_MODE: 1 | |
# Enable strict collect mode to catch file duplication problems in PKG/Carchive (onefile builds) or COLLECT | |
# (onedir builds) at build time. | |
PYINSTALLER_STRICT_COLLECT_MODE: 1 | |
# Enable strict handling of codesign errors for macOS bundles. | |
PYINSTALLER_STRICT_BUNDLE_CODESIGN_ERROR: 1 | |
# Enable strict verification of macOS bundles w.r.t. the code-signing requirements. | |
PYINSTALLER_VERIFY_BUNDLE_SIGNATURE: 1 | |
# Enable PEP 597 EncodingWarnings | |
PYTHONWARNDEFAULTENCODING: true | |
permissions: | |
contents: read # to fetch code (actions/checkout) | |
jobs: | |
tests: | |
runs-on: ${{ matrix.os }} | |
strategy: | |
matrix: | |
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13'] | |
os: ['windows-latest', 'ubuntu-22.04', 'macos-13', 'macos-14'] | |
# Split macOS workflows between macos-13 (x86_64) and macos-14 (arm64) | |
# runners to cover both architectures without running all combinations. | |
exclude: | |
- python-version: '3.8' | |
os: 'macos-14' | |
- python-version: '3.10' | |
os: 'macos-14' | |
- python-version: '3.12' | |
os: 'macos-14' | |
- python-version: '3.9' | |
os: 'macos-13' | |
- python-version: '3.11' | |
os: 'macos-13' | |
- python-version: '3.13' | |
os: 'macos-13' | |
fail-fast: false | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Set up Python ${{ matrix.python-version }} | |
uses: actions/setup-python@v5 | |
with: | |
python-version: ${{ matrix.python-version }} | |
- name: Install apt packages | |
if: startsWith(matrix.os, 'ubuntu') | |
run: | | |
sudo apt-get update -qq | |
sudo apt-get upgrade -qq | |
sudo apt-get install -qq --no-install-recommends \ | |
libcmocka-dev \ | |
libxml2-dev libxslt1-dev gfortran libatlas-base-dev \ | |
libespeak1 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 \ | |
libxkbcommon-x11-0 libxcb-icccm4 libxcb1 openssl \ | |
libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev \ | |
libxcb-shape0-dev libxcb-xkb-dev xvfb \ | |
libopengl0 libegl1 \ | |
libpulse0 libpulse-mainloop-glib0 \ | |
gstreamer1.0-plugins-base libgstreamer-gl1.0-0 \ | |
gir1.2-gtk-3.0 libgirepository1.0-dev \ | |
libfuse2 | |
# The following locales are required by test_basic::test_user_preferred_locale | |
# - en_US.UTF-8 | |
# - en_US.ISO8859-1 | |
# - sl_SI.UTF-8 | |
# - sl_SI.ISO8859-2 | |
# | |
# The following locale is used by test_basic::test_time_module_localized | |
# - cs_CZ.UTF-8 | |
- name: Install and enable additional locales | |
if: startsWith(matrix.os, 'ubuntu') | |
run: | | |
sudo apt-get update -qq | |
sudo apt-get install -qq --no-install-recommends locales | |
sudo locale-gen \ | |
en_US.UTF-8 \ | |
en_US \ | |
sl_SI.UTF-8 \ | |
sl_SI \ | |
cs_CZ.UTF-8 | |
locale -a | |
- name: Download AppImage tool | |
if: startsWith(matrix.os, 'ubuntu') | |
run: | | |
wget \ | |
https://github.com/AppImage/AppImageKit/releases/download/12/appimagetool-x86_64.AppImage \ | |
-O $HOME/appimagetool-x86_64.AppImage | |
chmod a+x $HOME/appimagetool-x86_64.AppImage | |
- name: Set cache dir | |
run: echo "pip_cache_dir=$(pip cache dir)" >> $GITHUB_ENV | |
shell: bash | |
- name: Fetch cache | |
id: cache-target | |
uses: actions/cache@v4 | |
with: | |
path: ${{ env.pip_cache_dir }} | |
key: ${{ runner.os }}-${{ matrix.python-version }} | |
- name: Check if bootloader code conforms to gnu90 C standard | |
if: startsWith(matrix.os, 'ubuntu') | |
run: | | |
# Compile bootloader | |
cd bootloader | |
CC="gcc -std=gnu90" python waf --tests all | |
- name: Check if bootloader code conforms to c99 ISO C standard (pedantic mode) | |
if: startsWith(matrix.os, 'ubuntu') | |
run: | | |
# Compile bootloader | |
cd bootloader | |
CC="gcc -std=c99 -pedantic" python waf --tests all | |
- name: Check if bootloader is buildable with --static-zlib option | |
if: startsWith(matrix.os, 'ubuntu') | |
run: cd bootloader && python waf --static-zlib --tests all | |
- name: Check if bootloader is buildable for Windows ARM | |
if: startsWith(matrix.os, 'windows') | |
run: | | |
cd bootloader | |
python waf --tests --target-arch=64bit-arm all | |
ls ../PyInstaller/bootloader/Windows-64bit-arm | |
- name: Update pip | |
run: python -m pip install --upgrade pip setuptools wheel build | |
# On (macos-14, python 3.10), (macos-13, python 3.11) and (macos-14, python 3.11) | |
# combinations the initial `setuptools` installation seems to contain `.opt-1.pyc` | |
# files in `__pycache__` directories. During the upgrade, `pip` fails to remove | |
# those directories (https://github.com/pypa/pip/issues/11835). | |
# | |
# `setuptools` 75.4 removed its vendored copy of `importlib_resources`, but due to | |
# the above issue, the effectively empty directory remains, turning `importlib_resources` | |
# into defunct namespace package, which causes some of our tests to fail. | |
- name: Work around potentially broken setuptools upgrade | |
shell: python | |
run: | | |
import sys | |
import pathlib | |
import shutil | |
import importlib.util | |
spec = importlib.util.find_spec('setuptools._vendor.importlib_resources') | |
if spec is None: | |
print("Did not find setuptools-vendored copy of importlib_resources.") | |
sys.exit(0) | |
elif spec.loader is not None: | |
print("Found a valid setuptools-vendored copy of importlib_resources.") | |
sys.exit(0) | |
print("Found a defunct setuptools-vendored copy of importlib_resources!") | |
# List the contents of importlib_resources package directory for debug purposes | |
def list_directory(path, pad=""): | |
for child in path.iterdir(): | |
if child.is_dir(): | |
print(f"{pad} + {child.name}") | |
list_directory(child, pad + " ") | |
else: | |
print(f"{pad} - {child.name} ({child.stat().st_size} bytes)") | |
for path in spec.submodule_search_locations: | |
print(f"Listing contents of {path}") | |
list_directory(pathlib.Path(path)) | |
# Remove | |
for path in spec.submodule_search_locations: | |
print(f"Removing {path}...") | |
shutil.rmtree(path) | |
- name: Compile bootloader | |
run: cd bootloader && python waf --tests all | |
- name: Download dependencies | |
run: pip download --dest=dist .[completion] && rm -f dist/pyinstaller-*.whl | |
shell: bash | |
- name: Build wheels | |
run: sh release/build-wheels | |
- name: Install PyInstaller | |
run: pip install --no-index --find-links=dist pyinstaller[completion] | |
- name: Check pyinstaller --help | |
run: python -m PyInstaller -h | |
- name: Install test dependencies (base tools) | |
run: | | |
pip install --progress-bar=off --upgrade --requirement tests/requirements-base.txt | |
- name: Install test dependencies (tools and libraries) | |
if: ${{ !endsWith(matrix.python-version, '-dev') }} | |
run: | | |
pip install --progress-bar=off --upgrade --requirement tests/requirements-libraries.txt | |
- name: Set up extra environment variables (non-Windows) | |
if: ${{ !startsWith(matrix.os, 'windows') }} | |
run: | | |
# Run Qt-based tests with offscreen backend. This seems to break QtWebEngine tests on Windows, so | |
# apply it only here, in non-Windows path. | |
echo "QT_QPA_PLATFORM=offscreen" >> $GITHUB_ENV | |
- name: Start display server | |
if: startsWith(matrix.os, 'ubuntu') | |
run: | | |
Xvfb :99 & | |
echo "DISPLAY=:99" >> $GITHUB_ENV | |
# Required on macOS >= 11 by tests that register custom URL schema. This could also be achieved by passing | |
# --basetemp to pytest, but using environment variable allows us to have a unified "Run test" step for | |
# all OSes. | |
# | |
# We now relocate the temporary directory to a fixed location on all OSes, in order to be able to generate | |
# artifacts out of failed tests. | |
- name: Relocate temporary dir | |
shell: bash | |
run: | | |
echo "PYTEST_DEBUG_TEMPROOT=$RUNNER_TEMP" >> $GITHUB_ENV | |
- name: Run tests | |
id: run-tests | |
run: > | |
pytest | |
-n 5 --maxfail 3 --durations 10 tests/unit tests/functional | |
# On all platforms, create a tarball to ensure that symlinks are preserved. Avoid using compression here, | |
# as the tarball will end up collected into artifact zip archive. | |
# To simplify this across platform, run this step in python and use python's tarfile module. | |
- name: Archive failed tests | |
if: ${{ failure() && steps.run-tests.outcome == 'failure' }} | |
shell: python | |
run: | | |
import os | |
import sys | |
import tarfile | |
try: | |
import getpass | |
user = getpass.getuser() or "unknown" | |
except Exception: | |
user = "unknown" | |
temproot = os.environ['PYTEST_DEBUG_TEMPROOT'] | |
pytest_name = f'pytest-of-{user}' | |
pytest_fullpath = os.path.join(temproot, pytest_name) | |
print(f"Input directory: {pytest_fullpath}!", file=sys.stderr) | |
output_file = os.path.join(temproot, 'archived-failed-tests.tar') | |
print(f"Output file: {output_file}!", file=sys.stderr) | |
assert os.path.isdir(pytest_fullpath) | |
assert not os.path.exists(output_file) | |
with tarfile.open(output_file, "w") as tf: | |
tf.add(pytest_fullpath, arcname=pytest_name, recursive=True) | |
print(f"Created {output_file}!", file=sys.stderr) | |
- name: Create artifact out of archived failed tests | |
if: ${{ failure() && steps.run-tests.outcome == 'failure' }} | |
uses: actions/upload-artifact@v4 | |
with: | |
name: failed-tests-${{ matrix.os }}-python-${{ matrix.python-version }} | |
path: '${{ env.PYTEST_DEBUG_TEMPROOT }}/archived-failed-tests.tar' | |
# Install and test PyInstaller Hook Sample, to ensure that tests declared in | |
# entry-points are discovered. | |
- name: Install hooksample | |
run: pip install "https://github.com/pyinstaller/hooksample/archive/v4.0rc1.zip" | |
# Augment _pyinstaller_hooks_contrib with bogus hooks that conflict with the hooks provided by hooksample. | |
# Due to (implicit) hook priority, the 3rd-party hooks should be chosen over _pyinstaller_hooks_contrib | |
# ones, and so the bogus hooks should never be ran. This applies to standard module hooks, as well as | |
# the pre-find-module-path and pre-safe-import-module hooks. | |
- name: Inject bogus hooks | |
shell: python | |
run: | | |
import os | |
from _pyinstaller_hooks_contrib import ( | |
stdhooks, | |
pre_safe_import_module, | |
pre_find_module_path, | |
) | |
with open(os.path.join(stdhooks.__path__[0], "hook-pyi_hooksample.py"), "w", encoding="utf-8") as f: | |
f.write('raise Exception("Wrong hook! Use the pyi_hooksample copy instead!")\n') | |
with open(os.path.join(pre_safe_import_module.__path__[0], "hook-pyi_hooksample.py"), "w", encoding="utf-8") as f: | |
f.write('raise Exception("Wrong hook! Use the pyi_hooksample copy instead!")\n') | |
with open(os.path.join(pre_find_module_path.__path__[0], "hook-pyi_hooksample.py"), "w", encoding="utf-8") as f: | |
f.write('raise Exception("Wrong hook! Use the pyi_hooksample copy instead!")\n') | |
- name: Run hooksample tests | |
run: | | |
# The ``run_tests`` script is invoked with the ``-c`` option to | |
# specify a ``pytest.ini``, rather than allowing pytest to find | |
# something unexpected in the filesystem (it searches from the root | |
# dir all the way to the top of the filesystem per | |
# https://docs.pytest.org/en/latest/customize.html). | |
python -m PyInstaller.utils.run_tests -c PyInstaller/utils/pytest.ini --include_only=pyi_hooksample. | |
test-alpine: | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- uses: actions/setup-python@v5 | |
with: | |
python-version: 3.x | |
- run: docker build -f alpine.dockerfile -t foo . | |
- run: > | |
docker run | |
foo | |
pytest | |
-n 5 --maxfail 3 --durations 10 tests/unit tests/functional | |
# Verify that installing from sdist works. This is mostly just a verification that the MANIFEST.in contains | |
# all the extras needed to compile the bootloader. | |
- run: | | |
git clean -xfdq . | |
pip install build | |
python -m build --sdist --outdir dist | |
docker build --target=wheel-factory -t bar -f alpine.dockerfile . | |
- run: | | |
sdist="$(ls dist)" | |
docker run -v "$PWD/dist:/io" bar ash -c " | |
pip install /io/$sdist | |
echo 'print(1 + 1)' > test.py | |
pyinstaller test.py | |
./dist/test/test | |
" | |
test-msys2: | |
runs-on: windows-latest | |
strategy: | |
matrix: | |
include: | |
- { sys: mingw64, env: x86_64 } | |
- { sys: mingw32, env: i686 } | |
- { sys: ucrt64, env: ucrt-x86_64 } | |
fail-fast: false | |
defaults: | |
run: | |
shell: msys2 {0} | |
steps: | |
- uses: msys2/setup-msys2@v2 | |
with: | |
update: true | |
msystem: ${{matrix.sys}} | |
install: >- | |
mingw-w64-${{matrix.env}}-gcc | |
mingw-w64-${{matrix.env}}-python | |
mingw-w64-${{matrix.env}}-python-pip | |
mingw-w64-${{matrix.env}}-python-wheel | |
mingw-w64-${{matrix.env}}-python-setuptools | |
mingw-w64-${{matrix.env}}-python-pywin32-ctypes | |
mingw-w64-${{matrix.env}}-python-packaging | |
mingw-w64-${{matrix.env}}-python-pytest | |
mingw-w64-${{matrix.env}}-python-pytest-xdist | |
mingw-w64-${{matrix.env}}-python-pytest-timeout | |
mingw-w64-${{matrix.env}}-python-psutil | |
mingw-w64-${{matrix.env}}-python-pywin32 | |
mingw-w64-${{matrix.env}}-python-pillow | |
- if: matrix.env != 'i686' | |
# numpy and pefile are unavailable for i686. Ignore numpy and install pefile via pip | |
run: pacman -S --noconfirm mingw-w64-${{matrix.env}}-python-numpy mingw-w64-${{matrix.env}}-python-pefile | |
- uses: actions/checkout@v4 | |
- run: | | |
uname -a | |
python --version | |
- name: Install PyInstaller | |
run: | | |
# Compile bootloader | |
cd bootloader | |
python waf --gcc --tests all | |
cd .. | |
# Install PyInstaller. | |
pip install --progress-bar=off .[completion] | |
# Make sure the help options print. | |
python -m PyInstaller -h | |
- name: Run tests | |
run: > | |
pytest | |
-n 5 --maxfail 3 --durations 10 tests/unit tests/functional |