Skip to content

Scheduled weekly dependency update for week 35 #1090

Scheduled weekly dependency update for week 35

Scheduled weekly dependency update for week 35 #1090

Workflow file for this run

name: Pull Request CI
# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the master branch
on:
workflow_dispatch:
pull_request:
paths:
- requirements-test-libraries.txt
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
permissions:
contents: read # to fetch code (actions/checkout)
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13', '3.14']
pyinstaller: ["https://github.com/pyinstaller/pyinstaller/archive/develop.zip"]
os: ["macos-15", "macos-15-intel", "ubuntu-24.04", "windows-latest"]
fail-fast: false
env:
# Rebuild bootloader when installing PyInstaller from develop branch
PYINSTALLER_COMPILE_BOOTLOADER: 1
steps:
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Limit dependencies to only new/changed libraries.
if: "${{ github.event.pull_request }}"
shell: bash
run: |
git fetch origin ${{ github.base_ref }}
set +e
# NOTE: we need to be compatible with both GNU diff and Apple/FreeBSD diff
diff \
<(git show origin/${{ github.base_ref }}:requirements-test-libraries.txt) \
<(git show HEAD:requirements-test-libraries.txt) \
| grep -E "^>" | sed "s/^> //" \
> requirements-test-libraries.txt
set -e
echo '-r requirements-test.txt' >> requirements-test-libraries.txt
cat requirements-test-libraries.txt
- name: Set up .NET Core for pythonnet tests
uses: actions/setup-dotnet@v5
with:
dotnet-version: '6.x'
# Install MariaDB Connector/C from official MariaDB Community Server
# repository; the version shipped with ubuntu may be too old for
# the "mariadb" python package.
#
# NOTE: the sha256sum for mariadb_repo_setup installation script is available at:
# https://mariadb.com/docs/server/server-management/install-and-upgrade-mariadb/installing-mariadb/binary-packages/mariadb-package-repository-setup-and-usage#versions
# (make sure to switch to "mariadb_repo_setup" tab!)
- name: Install MariaDB Connector/C
if: startsWith(matrix.os, 'ubuntu')
run: |
sudo apt-get update
sudo apt-get install -y wget apt-transport-https
wget https://downloads.mariadb.com/MariaDB/mariadb_repo_setup
echo "7325ac7755809ca3312b446bd832542421699298f25b701f9a111bb42df0c7c1 mariadb_repo_setup" | sha256sum -c -
chmod +x mariadb_repo_setup
sudo ./mariadb_repo_setup --skip-maxscale
sudo apt-get install -y libmariadb3 libmariadb-dev
- name: Install apt dependencies
if: startsWith(matrix.os, 'ubuntu')
run: |
sudo apt-get update
# Set up a virtual screen (for GUI libraries and pynput).
sudo apt-get install libxcb-xkb-dev xvfb
Xvfb :99 & echo "DISPLAY=:99" >> $GITHUB_ENV
# Install PyQt5 (qtmodern) dependencies.
sudo apt-get install -y 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 libopengl0 libegl1 \
libpulse0 libpulse-mainloop-glib0
# Install cairo dependencies.
sudo apt-get install -y libcairo2
# Install libdiscid (dependency of discid python package).
sudo apt-get install -y libdiscid0
# These are dependencies of gmsh
sudo apt-get install -y libglu1 libgl1 libxrender1 libxcursor1 libxft2 \
libxinerama1 libgomp1
# Required by PyGObject (dependency of toga/toga-gtk)
sudo apt-get install -y gir1.2-gtk-3.0 \
libcairo2-dev \
libgirepository1.0-dev gir1.2-girepository-2.0 \
libgirepository-2.0-dev gir1.2-girepository-3.0
# Required by pygraphviz
sudo apt-get install -y graphviz graphviz-dev
# Contemporary versions of eccodes PyPI wheels provide bundled copies of eccodes library; install a system
# copy to ensure that the bundled copy is properly collected and used at run-time.
sudo apt-get install -y libeccodes0
- name: Install brew dependencies
if: startsWith(matrix.os, 'macos')
run: |
# `pkg-config` is deprecated and superseded by `pkgconf`, but it is still pre-installed on the GitHub Actions
# runner. This leads to `brew link` errors when `pkgconf` is installed as part of dependencies. So for now,
# manually remove `pkg-config` (and specifically, the problematic `pkg-config@0.29.2`).
brew uninstall pkg-config || :
brew uninstall pkg-config@0.29.2 || :
# At the time of writing (end of August 2025), GHA macOS runner images started to pin CMake 3.31.6 via custom
# tap due to CMake 4.0 not being fully backwards compatible. However, this seems to be preventing us from
# installing `lsl`, which errors out with:
# Error: cmake is already installed from local/pinned!
# Please `brew uninstall cmake` first."
brew uninstall cmake || :
# Install cairo dependencies.
brew install cairo
# Install pango dependencies (weasyprint hook).
brew install pango
# Install libdiscid (dependency of discid python package).
brew install libdiscid
# Install lsl library for pylsl
brew install labstreaminglayer/tap/lsl
# This one is required by eccodes. Binary wheels with bundled eccodes library are provided for macOS 13+,
# but we install system package to ensure that the bundled copy is properly collected and used at run-time.
brew install eccodes
# Requires by pygraphviz
brew install graphviz
# On arm64 macOS runners, Homebrew is installed in /opt/homebrew instead of /usr/local prefix, and
# its headers and shared libraries are not in the default search path. Add them by setting CPPFLAGS
# and LDFLAGS. This is required by `pygraphviz`.
if [ "$(brew --prefix)" = "/opt/homebrew" ]; then
echo "CPPFLAGS=-I/opt/homebrew/include${CPPFLAGS+ ${CPPFLAGS}}" >> $GITHUB_ENV
echo "LDFLAGS=-L/opt/homebrew/lib${LDFLAGS+ ${LDFLAGS}}" >> $GITHUB_ENV
fi
- name: Install dependencies
shell: bash
run: |
# Upgrade to the latest pip.
python -m pip install -U pip setuptools
# Install hooks-contrib
pip install -e .
# Install test libraries
pip install --prefer-binary -r requirements-test-libraries.txt
# Additional implied dependencies of test libraries
# pyqtgraph requires Qt bindings - use PyQt5
pip show -qq pyqtgraph && pip install --prefer-binary PyQt5
# NOTE: specify minimum allowed version for sudachidict-* packages, to prevent pip from installing invalid
# SudachiDict_full-0.0.0-py3-none-any.whl due to --prefer-binary switch used with pip install...
pip show -qq sudachipy && pip install --prefer-binary "sudachidict-small>=20230927" "sudachidict-core>=20230927" "sudachidict-full>=20230927"
# pythainlp requires python-crfsuite, but fails to declare it as a requirement.
pip show -qq pythainlp && pip install --prefer-binary python-crfsuite
# tests for various trame-* packages require base trame package as well
pip show -qq trame-client trame-code trame-components trame-datagrid trame-deckgl trame-formkit trame-grid-layout trame-iframe trame-keycloak trame-leaflet trame-markdown trame-matplotlib trame-mesh-streamer trame-plotly trame-pvui trame-quasar trame-rca trame-router trame-server trame-simput trame-tauri trame-tweakpane trame-vega trame-vtk trame-vtk3d trame-vtklocal trame-vuetify trame-xterm && pip install --prefer-binary trame
pip show -qq trame-vtk && pip install --prefer-binary vtk pyvista nest-asyncio2 trame-vuetify
pip show -qq trame-mesh-streamer && pip install --prefer-binary vtk
pip show -qq trame-rca && pip install --prefer-binary vtk
# test_xarray_chunk requires dask in addition to xarray
pip show -qq xarray && pip install --prefer-binary dask
# Install additional intake plugins for test_intake_plugins
pip show -qq intake && pip install --prefer-binary intake-xarray
# test_langchain_with_ollama requires langchain-ollama to be installed together with langchain
pip show -qq langchain && pip install --prefer-binary langchain-ollama
# procrastinate depends on psycopg[pool]; the binary extra is required so that psycopg can be
# imported without a system-provided libpq.
pip show -qq procrastinate && pip install --prefer-binary psycopg[binary]
# Install PyInstaller
pip install ${{ matrix.pyinstaller }}
# PyTaskbar 0.1.0 does not ship TaskBarLib.tlb with its wheels anymore (in contrast
# to earlier releases under the PyTaskbarProgress name); apparently users are supposed
# to download it separately and copy it to their project's directory. Copying to the
# package's directory also seems to work, and is what our hook is expecting. So until
# we see what directions subsequent releases take, download and install the file.
# Applicable only to Windows (PyTaskbar is available only for Windows).
- name: Download and install TLB for PyTaskbar
if: startsWith(matrix.os, 'windows')
shell: python
run: |
import importlib.metadata
import importlib.util
import os
import sys
import urllib.request
import packaging.version
# Check if PyTaskbar is available, and at >= 0.1.0 version.
try:
version = importlib.metadata.version('PyTaskbar')
except importlib.metadata.PackageNotFoundError:
print("PyTaskbar dist not found.")
sys.exit() # N/A
print(f"PyTaskbar version: {version}")
version = packaging.version.parse(version)
if version < packaging.version.parse("0.1.0"):
print("PyTaskbar version is lower than 0.1.0.")
sys.exit()
# Determine package's path - attempting to import the package might raise
# missing library error, so look up the spec and module's search location
# in it.
spec = importlib.util.find_spec('PyTaskbar')
if spec is None:
print("PyTaskbar spec not found.")
sys.exit()
location = spec.submodule_search_locations[0]
print(f"Package location: {location}")
# Check if the .tlb file already exists
tlb_file = os.path.join(location, 'TaskbarLib.tlb')
if os.path.isfile(tlb_file):
print(f"TLB file already exists.")
sys.exit()
# Download the .tlb file from GitHub releases
tlb_url = f"https://github.com/N3RDIUM/PyTaskbar/releases/download/{version}/TaskbarLib.tlb"
print(f"Downloading TLB file from: {tlb_url}")
urllib.request.urlretrieve(tlb_url, tlb_file)
# Some python versions come with initial `setuptools` installation that seems to contain `.opt-1.pyc`
# files in `__pycache__` directories. During the upgrade, `pip` fails to remove those directories
# (see: 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 a defunct namespace package, which causes some of our tests to fail.
#
# Similar issue arises when upgrading to `setuptools` 82.0.0, which removed `pkg_resources` package;
# the defunct namespace package arising from the left-over directory causes error in our `pkg_resources`
# run-time hook (which would otherwise not be collected at all).
- name: Work around potentially broken setuptools upgrade
shell: python
run: |
import sys
import pathlib
import shutil
import importlib.util
PACKAGES = [
'setuptools._vendor.importlib_resources',
'pkg_resources',
]
def fix_package(package_name):
try:
spec = importlib.util.find_spec(package_name)
except ImportError:
spec = None # parent package (e.g., setuptools or setuptools._vendor) does not exist
if spec is None:
print(f"Did not find {package_name}.")
return
elif spec.loader is not None:
# Not a namespace package (i.e., directory with just __pycache__ sub-directory)
print(f"Found a valid copy of {package_name}.")
return
print(f"Found a defunct copy of {package_name}!")
# List the contents of 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)
for package in PACKAGES:
fix_package(package)
- name: Run tests
run: pytest -v -n logical
# Conditionally enable slow tests, so that they are ran only if
# their corresponding packages are explicitly installed but not
# if they are installed as dependencies of some other package.
- name: Check if slow tests are required (scikit-learn)
id: check-scikit-learn
shell: bash
run: |
grep -E "scikit-learn" requirements-test-libraries.txt && echo "AVAILABLE=yes" >> $GITHUB_OUTPUT || echo "AVAILABLE=no" >> $GITHUB_OUTPUT
- name: Run slow tests (scikit-learn)
if: ${{ steps.check-scikit-learn.outputs.AVAILABLE == 'yes' }}
run: pytest -v -n logical -m slow -k sklearn
- name: Check if slow tests are required (scikit-image)
id: check-scikit-image
shell: bash
run: |
grep -E "scikit-image" requirements-test-libraries.txt && echo "AVAILABLE=yes" >> $GITHUB_OUTPUT || echo "AVAILABLE=no" >> $GITHUB_OUTPUT
- name: Run slow tests (scikit-image)
if: ${{ steps.check-scikit-image.outputs.AVAILABLE == 'yes' }}
run: pytest -v -n logical -m slow -k skimage
- name: Check if slow tests are required (vtk)
id: check-vtk
shell: bash
run: |
grep -E "^vtk==" requirements-test-libraries.txt && echo "AVAILABLE=yes" >> $GITHUB_OUTPUT || echo "AVAILABLE=no" >> $GITHUB_OUTPUT
- name: Run slow tests (vtk)
if: ${{ steps.check-vtk.outputs.AVAILABLE == 'yes' }}
run: pytest -v -n logical -m slow -k test_vtkmodules