Skip to content

fix: pin pytantan to 0.1.3 and add defensive lazy import#67

Merged
nextgenusfs merged 1 commit into
mainfrom
pin-pytantan-013-and-defensive-import
May 25, 2026
Merged

fix: pin pytantan to 0.1.3 and add defensive lazy import#67
nextgenusfs merged 1 commit into
mainfrom
pin-pytantan-013-and-defensive-import

Conversation

@nextgenusfs

Copy link
Copy Markdown
Owner

Summary

Belt-and-braces fix for the recurring Illegal instruction SIGILL when running the funannotate2 Docker image under Rosetta 2 on Apple Silicon. Combines a known-working pytantan version with defensive import handling so that even a broken pytantan installation can no longer take down the entire CLI.

Changes

1. Pin pytantan to v0.1.3

  • pyproject.toml: pytantan>=0.1.4pytantan>=0.1.3
  • pixi.toml: pytantan = ">=0.1.4"pytantan = "==0.1.3"
  • pixi.lock: regenerated via pixi update pytantan (now resolves to 0.1.3)

v0.1.3 was the last release with a straightforward CMake gate where HAVE_AVX2=OFF is sufficient to produce a portable build. v0.1.4's runtime SIMD dispatch added complexity without giving us anything we use — funannotate2 only consumes RepeatFinder and default_scoring_matrix, which are identical in both versions.

2. Restore the proven Dockerfile recipe

RUN SKBUILD_CMAKE_ARGS="-DHAVE_AVX2:BOOL=OFF;-DAVX2_C_FLAGS:STRING=" \
    pip install --no-deps --no-cache-dir --force-reinstall \
        "pytantan @ git+https://github.com/althonos/pytantan.git@v${PYTANTAN_VERSION}"

SKBUILD_CMAKE_ARGS is scikit-build-core's own env var (semicolon-separated CMake list) and is passed directly into the inner cmake invocation, bypassing the env-var filtering that affected previous attempts with CMAKE_ARGS. The objdump + file-presence guards are retained as cheap insurance — they will fail the build loudly if any AVX2 instructions sneak in.

3. Defensive lazy import in funannotate2/fastx.py

Moved from pytantan.lib import RepeatFinder, default_scoring_matrix from module top into softmask_fasta(), wrapped in try/except ImportError → raises a descriptive RuntimeError. As a result:

  • funannotate2 --help, funannotate2 install, etc. never crash even if pytantan is broken in the user's environment.
  • Only an actual softmasking call surfaces an error, and the message is actionable.

4. Graceful handling in funannotate2/predict.py

Wrapped the softmask_fasta() call in try/except (RuntimeError, ImportError):

  • Restores the original FASTA on failure (no half-renamed state).
  • Logs a critical message pointing at external repeat maskers as a workaround.
  • Exits cleanly with code 1.

Validation

  • All 15 existing tests in tests/unit/test_predict.py + test_fastx.py pass.
  • All 16 tests in test_predict_functions.py, test_predict_comprehensive.py, test_fastx_additional.py, test_fastx_more.py pass.
  • Verified manually that funannotate2.fastx imports cleanly with pytantan blocked at the meta-path level, and that softmask_fasta() then raises a descriptive RuntimeError only when invoked.

Post-merge action

The docker.yml workflow only publishes :latest on release tags or manual workflow_dispatch. After merging this PR, run Actions → Build and Publish Docker Image → Run workflow on main (with push=true) to republish :latest with the working v0.1.3 image.


Pull Request opened by Augment Code with guidance from the PR author

Reverts pytantan to the v0.1.3 build recipe that was confirmed working in
production, and moves the pytantan import inside softmask_fasta() so a
broken pytantan installation no longer SIGILLs unrelated funannotate2
subcommands (--help, install, etc.).

- pyproject.toml / pixi.toml / pixi.lock: pin pytantan to 0.1.3 (PyPI).
  v0.1.4's runtime SIMD dispatch has been unreliable on x86_64 hosts
  without AVX2 (notably Rosetta 2 on Apple Silicon). v0.1.3 builds cleanly
  with HAVE_AVX2:BOOL=OFF and funannotate2 only uses RepeatFinder /
  default_scoring_matrix which exist in both versions.

- Dockerfile: restore the minimal SKBUILD_CMAKE_ARGS-based rebuild
  (scikit-build-core's own env var, semicolon-separated, bypasses the
  env-var filtering that affects CMAKE_ARGS). Keep the objdump and
  file-presence guards as cheap insurance against any regression.

- funannotate2/fastx.py: defer 'from pytantan.lib import ...' to inside
  softmask_fasta(); raise a descriptive RuntimeError on ImportError so
  the failure mode is actionable instead of a SIGILL at process start.

- funannotate2/predict.py: wrap the softmask_fasta() call in try/except,
  restore the original FASTA on failure, log critical message, and exit
  cleanly with code 1.
@nextgenusfs nextgenusfs marked this pull request as ready for review May 25, 2026 06:21
@nextgenusfs nextgenusfs merged commit 2b514f1 into main May 25, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant