ci: refresh Python matrix and ASE compat for meson#27
Merged
Conversation
Python 3.8 (EOL Oct 2024) and 3.9 (EOL Oct 2025) are no longer supported upstream. Replace them with 3.13 in both the test matrix and the cibuildwheel matrix. The Python 3.8 macOS-arm64 exclusion is dropped along with its trigger. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ase.constraints.full_3x3_to_voigt_6_stress was relocated to ase.stress in newer ASE releases, hard-failing the import on Python 3.13 + ASE 3.28. Add a try/except import shim in both extxyz.utils and the test that imports the helper directly, matching the fix from PR #25. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Both workflows previously fired only on push/PR against master, so PRs targeting the long-running meson migration branch never ran CI. Add meson to the push and pull_request branch filters so this and future meson-targeted PRs get checked. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Linux: bump CIBW_MANYLINUX_X86_64_IMAGE to manylinux_2_28. scipy 1.17 (released since the last green CI in Nov 2025) dropped manylinux2014 wheels for cp311+, so the test phase fell back to a from-source scipy build that needs OpenBLAS in the container. - macOS Intel (macos-15-intel): bump MACOSX_DEPLOYMENT_TARGET from 14.0 to 15.0. Brew on macos-15 runners now ships PCRE2 with a 15.0 minimum, so building against it under a 14.0 target tripped delocate's library-version check. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
meson-python errored on Windows wheel-packaging because Meson lists an MSVC import library (_extxyz.cpXX-win_amd64.lib) in its install plan that python.extension_module() never actually creates. Add tool.meson-python.wheel.exclude = ["**/*.lib"] to drop those phantom entries from the wheel manifest before the copy step, then put windows-latest back into the matrix. If this works, supersedes the long thread of attempts in the disabled-Windows commit (688316f). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The wheel.exclude fix solved the meson-python install error, revealing the next-layer Windows issue: cextxyz.py loads the extension via ctypes.CDLL and calls extxyz_read_ll, etc. directly, but MSVC defaults to no exported symbols, so ctypes raised AttributeError on first lookup. Add libextxyz/_extxyz.def listing the five symbols cextxyz.py calls, and pass vs_module_defs to python.extension_module(). The vs_module_defs kwarg is a no-op on non-MSVC compilers, so gnu_symbol_visibility='default' continues to handle GCC/Clang. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
cibuildwheel's default repair-wheel-command on Windows is empty (unlike auditwheel on Linux and delocate on macOS), so the built .pyd shipped with no bundled PCRE2 DLL. ctypes.CDLL then failed at import time with "Could not find module ... or one of its dependencies". Wire delvewheel into the Windows pipeline by installing it in before-build and pointing repair-wheel-command at it. delvewheel reads PATH (which already includes C:/vcpkg/installed/x64-windows/bin via [tool.cibuildwheel.windows.environment]) to find pcre2-8.dll. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
On Linux/macOS cextxyz.py loaded libc via find_library('c') and
called fopen/fclose/ftell/fseek directly, then passed the FILE*
to extxyz_read_ll. That works because libc is system-wide and
both ends share one C runtime.
On Windows find_library('c') returns None (TypeError on
ctypes.CDLL(None)), and even if we loaded msvcrt.dll the
FILE* it returns is generally incompatible with the ucrtbase
runtime that _extxyz.pyd is linked against — that's a classic
CRT-mismatch crash waiting to happen.
Fix: add thin extxyz_fopen/fclose/ftell/fseek wrappers in
extxyz.c, export them via _extxyz.def, and have cextxyz.py
pick that path on Windows. The wrappers compile inside _extxyz
itself so they always share its CRT. Linux/macOS retain the
existing libc path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
iread() checked isinstance(file, PosixPath), which is a Linux/ macOS-only subclass. On Windows tmp_path / 'foo.xyz' returns a WindowsPath, so the check fell through and the path object went into the index branch where iteration produced "WindowsPath object is not iterable". Switch to isinstance(file, (str, Path)) — pathlib.Path is the abstract base for both PosixPath and WindowsPath. cfopen already wraps with str(), so the rest of the path is unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
windows-latest defaults to PowerShell, which can't parse bash's [[ =~ ]] regex syntax — it tripped on the Check tag step after every Windows wheel job (PowerShell ParserError), turning otherwise-green test runs red. Pin shell: bash on both Check tag and Deploy to PyPI; Git for Windows supplies bash on the hosted runners. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
QUIP retired the example QUIP/.github/workflows/Makefile.inc that the old build step copied, breaking every test job since. QUIP now ships first-class Meson support, so build libAtoms directly with meson setup + meson compile. Adjust the Fortran-executable step to point QUIP_LDFLAGS and QUIP_F90FLAGS at Meson's build layout: liblibAtoms.so under src/libAtoms, .mod files in the target-private *.p dir alongside it. Use libopenblas (Meson QUIP's BLAS choice) instead of separate libblas/liblapack. Drop the QUIP_ARCH and HAVE_GAP env vars that only made sense under the old Makefile.inc workflow. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
QUIP's src/Potentials/meson.build references the GAP variable unconditionally, so meson setup -Dgap=false errors with "Unknown variable 'GAP'" before any target builds. We only need libAtoms, but pass -Dgap=true to satisfy the configure step. The recursive clone already pulls the GAP submodule. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
QUIP's Fortran modules carry the _module suffix (libatoms_module.mod, system_module.mod, ...), so the original find for 'system.mod' produced no match and gfortran got an empty -I argument. Switch the probe to libatoms_module.mod and fail loudly if it's missing instead of silently passing -I with no path. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The find result was relative to PWD, but make runs from
libextxyz/ — gfortran resolved -I against libextxyz/QUIP/...
which doesn't exist. Anchor the find to ${PWD} so the
returned path is absolute.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
QUIP's libAtoms references f90wrap_abort_ which is provided by the f90wrap_stub static library (f90wrap_stub.F90 lives in a separate target so it isn't linked into Python wrappers). 'meson compile libAtoms' alone leaves libf90wrap_stub.a unbuilt, so the standalone Fortran linker errored on "undefined reference to f90wrap_abort_". Compile both targets and add -lf90wrap_stub to QUIP_LDFLAGS. Verified locally on macOS. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
call print(at) is purely diagnostic — it dumps the parsed Atoms object to stdout and isn't part of the read/write contract. On current QUIP/libAtoms (Meson HEAD as of April 2026) it segfaults inside the Properties dictionary print iterator. Comment it out so the round-trip test stays functional. Re-enable after the libAtoms regression is fixed upstream or fextxyz is taught the new dictionary layout. Verified locally on macOS arm64 with USE_FORTRAN=T pytest: 31 passed, 2 skipped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closed
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Verified locally on macOS arm64 with Python 3.13.13 + ASE 3.28.0: `pytest tests/` → 31 passed, 2 skipped.
Note: this PR targets the long-running `meson` migration branch (#17), not master.
Test plan
🤖 Generated with Claude Code