Contents
- 1 Overview of Aptest
- 2 License
- 3 How to run Aptest
- 4 Python virtual environments
- 5 Supported packages
- 6 Package locations
- 7 Building packages
- 8 Testing packages
- 9 Build/test with cibuildwheel
- 10 Things to be careful of
- 11 Examples
- 12 Making internal development releases
- 13 Release procedure
- 14 Details
- 15 Command-line arguments
- 16 Changelog
Aptest is a command-line programme that can build, test and release (to https://pypi.org) multiple Artifex Python packages together.
Aptest is hosted at https://github.com/ArtifexSoftware/aptest.
GNU Affero General Public License v3.0 only.
- See file COPYING.
Aptest can be run in various ways:
Run directly from local Aptest Git checkout, using command
aptest/aptest.py:git clone git@github.com:ArtifexSoftware/aptest.git aptest/aptest.py ...
Install into current venv from local Aptest Git checkout, and use command
aptest:git clone git@github.com:ArtifexSoftware/aptest.git pip install ./aptest aptest ...
Install into current venv from remote Aptest Git repository, and use command
aptest:pip install git+ssh://git@github.com/ArtifexSoftware/aptest.git aptest ...
Use pipx with local Aptest Git checkout:
git clone git@github.com:ArtifexSoftware/aptest.git pipx run ./aptest ...
Use pipx with remote Aptest Git repository:
pipx run artifex_aptest@git+ssh://git@github.com/ArtifexSoftware/aptest.git ...
If one is already in a venv:
- Aptest will use the venv directly, for example the build command will install packages into this venv.
Otherwise:
- Aptest will create, enter and use its own venv,
called
venv-aptest-<pthonversion>-<wordsize>. - For convenience,
a symbolic link
venv-aptestwill be created that points to this venv.
langchain_pymupdf_layoutmupdfpdf2docxpdf_feature_inspectorpymupdfpymupdf4llmpymupdf_layoutpymupdfprosmartofficesmartoffice-marinasmartoffice-neo
Notes:
Only one of
smartoffice,smartoffice-marinaandsmartoffice-neocan be specified.mupdf,smartoffice,smartoffice-marinaandsmartoffice-neoare pseudo packages.They are not built into python wheels, instead:
mupdfis built intopymupdf.smartoffice,smartoffice-marinaandsmartoffice-neoare built intopymupdfpro.
See the -i option.
- A local checkout.
- Specific branch, tag or sha on remote git repository.
- https://pypi.org.
See the -i option.
For each package:
If package was specified with
pip:...- A wheel will be downloaded and installed from https://pypi.org.
Otherwise:
If package was specified with
git:...we clone/update a local checkout.The package is built locally into a wheel with
pip wheel.This will typically take place in an internal pip venv.
The wheel is installed into the current venv.
Note that the wheel will be specific to the current system and might not work on other systems with the same OS.
For example on Linux it will require at least the current system's glibc.
If you need a more portable wheel, use the cibw command.
The wheel is added to a local pypi-style PEP 503 package repository.
We use pip's
--extra-index-urloption to refer to our internal package repository.Thus pip will use previously built package wheels as prerequisites, as required.
See the build command.
- We run tests for each package, using pytest.
- Packages on https://pypi.org do not contain test suites, but one can specify a second package location to be used for testing, for example a local checkout or remote git repository.
- One can generate traces of MuPDF calls by setting environment variables in debug builds. For details see: https://mupdf.readthedocs.io/en/latest/language-bindings.html#environmental-variables
See the test command.
- Instead of separately building and testing packages, Aptest can use cibuildwheel.
- This builds a wheel, and runs tests using pytest.
- We add each wheel to our internal package repository.
- We set
PIP_EXTRA_INDEX_URLto point to our internal package repository. - cibuildwheel uses pip internally so this ensures that previously-built prerequisite wheels will be installed as required.
- Note that, unlike testing with the test command, prerequisite packages can override packages specified to Aptest. We try to avoid this by setting PYMUPDF_SETUP_VERSION but generally one should use build and test when testing non-standard versions.
See the cibw command.
Aptest tries to be cautious when building/rebuilding and, by default, it will remove the contents of the wheelhouse before building anything, so don't assume previous builds will be available.
So for example when building pymupdf4llm, if one intends to use the new build of pymupdf4llm with a similar new build of pymupdf (instead of pymupdf from pypi.org), then one should also build pymupdf, for example with:
aptest/aptest.py -m=git: -p=git: --4llm pymupdf4llm buildUsually rebuilding pypmupdf like this will be faily quick.
[Also see Python virtual environments for information about where wheels are generated/installed.]
Using local checkouts, build packages pymupdf, pymupdfpro and pymupdf_layout
(putting wheels into directory aptest-wheelhouse/),
install (into current venv or venv-aptest-<pthonversion>-<wordsize>)
and test:
aptest/aptest.py -p PyMuPDF --pro PyMuPDFPro -m mupdf --layout sce build test
Similarly build, install and test pymupdf, pymupdfpro and pymupdf_layout using
central git repositories:
aptest/aptest.py -p git: --pro git: --layout git: build test
Make release, building/testing on Github, downloading to local machine, and uploading to https://pypi.org (also see Release procedure):
aptest/aptest.py --release-1 aptest/aptest.py --release-2 aptest/aptest.py --release-3 aptest/aptest.py --release-4 aptest/aptest.py --release-5 aptest/aptest.py --release-6
Build/test pymupdf, pymupdfpro and pymupdf-layout using cibuildwheel,
getting packages from different locations:
aptest/aptest.py -r @github -p pip: --pro PyMuPDFPlus --layout git: cibw
Test current pymupdf release with latest test suite in central git:
aptest/aptest.py -p pip: -p git: build test
Test current pymupdf release with test suite in local checkout:
aptest/aptest.py -p pip: -p PyMuPDF build test
Runs specific Github workflow PyMuPDFPlus/.github/workflows/test_multiple.yml, on windows only:
aptest/aptest.py -r @github --remote-github-yml test_multiple.yml --pro PyMuPDFPlus --remote-github-yml-inputs --remote-github-runners windows
Test https://pypi.org's pymupdf, pymupdfpro and pymupdf_layout with the test
suites on central git:
aptest/aptest.py -r @github -p pip: --pro pip: --layout pip: -p git: --pro git: --layout git: build test
Download wheels from a previous Aptest Github workflow run:
aptest/aptest.py -r @github --aptest aptest --remote-github-workflow-id 21760695687
Test Aptest itself:
aptest/aptest.py --aptest aptest test
Build/test pymupdfpro with alternative smartoffice-neo:
aptest/aptest.py --smartoffice-neo git: --pro git: build test
Build/test pymupdfpro with alternative smartoffice-marina:
aptest/aptest.py --smartoffice-marina git: --pro git: build test
Run pymupdf_layout gnn tests with mupdf version 1.27.2, current pymupdf in git, and local checkout sce/ of pymupdf_layout (this assumes that the DocLayNet dataset has been downloaded, see Using DocLayNet dataset):
aptest/aptest.py --test-gnn-det eval/eval_pymupdf_layout.py -m=git:'-t 1.27.2' -p=git: --layout=sce test-gnn
It can be useful to build wheels for commonly-used systems from the latest code in central git, and make them generally available for testing.
First create a separate wheelhouse directory, with a special file that prevents Aptest from deleting it. This allows one to have multiple wheel versions in the same place:
mkdir -p wheels-testtouch wheels-test/_aptest_wheelhouse_preserve
Build wheels on Github,
forcing version 1.28.0a1 for packages starting with pymupdf by setting PIPCL_CHANGE_VERSIONS.
This will default to creating wheels for windows-x64, linux-x64 and macos-arm64:
aptest/aptest.py --wheelhouse wheels-test -m=git: -p=git: --layout=git: --4llm=git: -r @github cibw -e 'PIPCL_CHANGE_VERSIONS=^pymupdf.* 1.28.0a1'
Upload wheels and pypi database to web server:
aptest/aptest.py --wheelhouse wheels-test draft --draft-location julian@ghostscript.com:public_html/wheels-test/
View wheels on web server at:
https://ghostscript.com/~julian/wheels-test
Install wheels from the web server with one of:
pip install --pre --upgrade --extra-index-url https://ghostscript.com/~julian/wheels-test/simple pymupdf4llmpip install --extra-index-url https://ghostscript.com/~julian/wheels-test/simple pymupdf4llm==1.28.0a1
Instructions for releasing wheels for:
pdf4llmpymupdfpymupdf4llmpymupdf_layoutpymupdfpro
Get local checkout of latest version of each package, corresponding to what will be released.
Ensure that pymupdf's
setup.pyspecifies the correct mupdf version.If this is not the case, update, commit, push, and wait for the next overnight tests to pass before making the release.
Ensure the version number is correct in all packages.
- All packages should have the same version number.
- Version numbers are always defined in
setup.py. - Version numbers may also be defined in other files such as
READMEandCHANGES. pymupdfhas a test that checks version numbers inchanges.txtetc are consistent withsetup.py.
Ensure that
pymupdf's Github issues andchanges.txtare synchronised.- Go to https://github.com/pymupdf/PyMuPDF/issues.
- For all issues that are labeled as
Fixed in next release, ensure that they are labelled as fixed inchanges.txt. - For all issues mentioned as fixed in
changes.txt, ensure that the corresponding Github issue is labelled asFixed in next release.
Test local checkouts of all packages on Github machines:
aptest/aptest.py -r @github -p PyMuPDF --pro PyMuPDFPro --layout sce --4llm pymupdf4llm --pdf4llm pymupdf4llm cibwIn ~/.aptest, specify package sources for releases.
This is done with upper-case versions of the usual package-specifier options, so that different --release-* options can select different subsets (see -i's upper-case-package names section).
To use local checkouts:
-P PyMuPDF --PRO PyMuPDFPlus --LAYOUT sce --4LLM pymupdf4llm --PDF4LLM pymupdf4llmOr to use specific sha's for each package:
-P 'git:--sha ...' --PRO 'git:--sha ...' --LAYOUT 'git:--sha ...' --4LLM 'git:--sha ...' --PDF4LLM 'git:--sha ...'Or to use the latest remote versions in git:
-P git: --PRO git: --LAYOUT git: --4LLM git: --PDF4LLM git:In ~/.aptest, specify an empty release wheelhouse directory, for example:
--wheelhouse-release release-1.27.2This will eventually hold all release wheels and sdists prior to them being uploaded to https://pypi.org.
Build wheels for all packages:
aptest/aptest.py --release-1aptest/aptest.py --release-2aptest/aptest.py --release-3aptest/aptest.py --release-4aptest/aptest.py --release-5aptest/aptest.py --release-6These commands can be manually run in parallel using individual terminals.
On success this will populate the release wheelhouse with all wheels and sdists
Also see:
Make manual tests of the generated wheels before uploading.
Install from local wheels:
Use the location specified by --wheelhouse-release in ~/.aptest, with
pip install's--extra-index-url, for example:pip install --extra-index-url release-1.27.2 pdf4llm pymupdfpro
Or upload to, and install from, a web server:
aptest/aptest.py draft --draft-location julian@ghostscript.com:public_html/wheels-1.27.2/--wheelhouse release-1.27.2.pip install --extra-index-url https://ghostscript.com/~julian/wheels-1.27.2/simple pdf4llm pymupdfpro
Test the wheels:
- Enter a venv.
pip install pytestpytest PyMuPDF/testsetc.
Make the release by uploading all wheels and sdists to https://pypi.org/:
aptest/aptest.py uploadRelease pyodide wheel.
2026-06-15: pypi.org now accepts pyodide wheels.
- See: pymupdf/PyMuPDF#5025
- Need to update aptest.py to include pyodide wheels in upload.
Old:
Copy/rsync the pyodide wheel in the release directory to
julian@ghostscript.com:public_html/pyodide/, for example:rsync -ai release-1.27.2/pymupdf-1.27.2-cp313-abi3-pyodide_2025_0_wasm32.whl julian@ghostscript.com:public_html/pyodide/This will be available in: https://ghostscript.com/~julian/pyodide/.
Tell
@jamieabout the Pyodide wheel.[2026-01-30: hopefully we'll have a more official location soon.]
Update central repositories:
Repositories are:
PyMuPDFPyMuPDFPropymupdf4llmsce
If building with local checkouts, push each to github.
Tag each repository:
We use the version number as the tag, e.g.
1.26.7.For each repository:
git tag <version> git push origin <version>
Extra updates to Github's
pymupdfrepository.Click
Draft a new release.In
Choose a tag, select the tag<version>.In
Release titleenterPyMuPDF-<version> released.Add header text explaining pip install, similar to previous releases. For example:
Wheels for Windows, Linux and MacOS, and the sdist, are available on https://pypi.org and can be installed in the usual way, for example: ``` python -m pip install --upgrade pymupdf ```
Paste the release's changelog into the text field.
Modify any ReST-style links to work as markdown, e.g. rely on Github interpreting
#1234as a link to issue 1234.Ensure that
Set as the latest releaseis checked.Ensure that
Create a discussion for this releaseis checked, withCategory: Announcements.Click on
Publish release.This will also create
.zipand.tar.gzarchives for download from github.Go to the
Discussionspage and pin the announcement discussion so that it appears at the top of the page.Unpin any previous release's announcement discussion.
For all Github issues that are labeled as
fixed in next release, close the issue with textFixed in PyMuPDF-<version>.Check in the release announcement that all fixed issues are now shown as closed.
If the new release uses a new version of MuPDF, optionally remove all code that is specific to the previous major release of MuPDF. E.g. grep for
FZ_VERSIONormupdf_version_tuple.Update https://pymupdf.readthedocs.io:
- Go to: https://readthedocs.io
- Click
Log in. - Click on
Read the Docs Community. - Select login using email.
- Enter email address and shared password.
- Go to PyMuPDF.
- Click on Builds.
- Click on top item's refresh button
Rebuild version.
Post to Discord
#pymupdf_tech.Send email to
pymupdf-marketing@artifex.com.Subject:
PyMuPDF-<version> releasedBody:
PyMuPDF-<version> has just been released. See: https://github.com/pymupdf/PyMuPDF/discussions/<announcement-id>
Possible post-release changes:
For all projects.
- Increment version in all package
setup.pyfiles.
Extra post-release changes for
pymupdf.In
pymupdf'schanges.txt:- Add date of release that was just made.
- Add title for next release
**Changes in version <next-version>**.
In
pymupdf's.github/ISSUE_TEMPLATE/bug_report.yml:Add version of next release to drop-down list of versions.
(This is required for tests to pass.)
- Increment version in all package
Aptest can transparently re-run itself in remote locations:
- Remote machine (with ssh/rsync).
- Github runner (push to unique(ish) branches and run a workflow).
See the -r option.
If Aptest is not already running inside a Python venv, it automatically creates a venv and re-runs itself inside it.
- The build command builds and installs into the current venv.
- The test command tests packages that are installed in the current venv.
See the -v option.
If --pytest-junit-xml is specified,
then when running pytest with the test and cibw commands,
Aptest specifies --junit-xml=aptest-wheelhouse/<package-name>-pytest-junit.xml,
which generates an .xml file containing the test results.
The .xml file is also copied back to local machine along with .whl files if -r is used.
Also see https://docs.pytest.org/en/stable/how-to/output.html#creating-junitxml-format-files.
Packages can be cleaned before building or when populating.
See the --clean-git, --clean-setup and --clean-setup-all options.
Cibuildwheel needs a system install of required python version(s).
On Macos:
Installing python versions with brew does not seem to work - cibuildwheel cannot find them.
What does work is to use the official installers at https://python.org.
These commands install the latest builds of Python, as of 2026-02-25:
wget https://www.python.org/ftp/python/3.10.11/python-3.10.11-macos11.pkg && sudo installer -pkg python-3.10.11-macos11.pkg -target / wget https://www.python.org/ftp/python/3.11.9/python-3.11.9-macos11.pkg && sudo installer -pkg python-3.11.9-macos11.pkg -target / wget https://www.python.org/ftp/python/3.12.10/python-3.12.10-macos11.pkg && sudo installer -pkg python-3.12.10-macos11.pkg -target / wget https://www.python.org/ftp/python/3.13.12/python-3.13.12-macos11.pkg && sudo installer -pkg python-3.13.12-macos11.pkg -target / wget https://www.python.org/ftp/python/3.14.3/python-3.14.3-macos11.pkg && sudo installer -pkg python-3.14.3-macos11.pkg -target /
To install python-3.14t:
Run:
wget https://www.python.org/ftp/python/3.14.0/python-3.14.0-macos11.pkg
Create a file called
choicechanges.plistcontaining:<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <array> <dict> <key>attributeSetting</key> <integer>1</integer> <key>choiceAttribute</key> <string>selected</string> <key>choiceIdentifier</key> <string>org.python.Python.PythonTFramework-3.14</string> </dict> </array> </plist>Run:
sudo installer -pkg python-3.14.0-macos11.pkg -applyChoiceChangesXML choicechanges.plist -target /
Also see: https://docs.python.org/3/using/mac.html.
(2026-02-06) With cibw we do not test with python-3.14 on Windows
When cibuildwheel internally attempts to install packages with
pip install(withPIP_EXTRA_INDEX_URLpointing to our piprepo wrapping of aptest-wheelhouse), pip complains:WARNING: Location 'file://D:/a/aptest/aptest/aptest-wheelhouse/simple/pymupdf/' is ignored: it is neither a file nor a directory. INFO: pip is looking at multiple versions of pymupdfpro to determine which version is compatible with other requirements. This could take a while. ERROR: Could not find a version that satisfies the requirement PyMuPDF==1.27.1 (from pymupdfpro) (from versions: ...) ERROR: No matching distribution found for PyMuPDF==1.27.1I.e. prerequisite packages are not found, despite being in
aptest-wheelhouse.This failure does not happen with python-3.10-3.13.
Package piprepo requires package pkg_resources,
which is part of setuptools,
but only setuptools<81.
Running Aptest within a Visual Studio session has been known to give confusing results, possibly due to using a different working directory.
So it's recommended to run Aptest within a standard Windows terminal instead.
Aptest allows different keys to be used when it runs operations such as git commands, pypi uploads and Github ReST operations.
- Keys can be in files or environment variables.
- Keys are selected by matching a prefix against git remotes, urls etc.
- If the -r option is used to defer to a remote machine,
all specific key files are copied to the remote machine.
- This is probably only usable if key files are in the current directory.
- This obviously has security implications.
- If the -r option is used to defer to a Github runner with -r @github, we rely on the Github Aptest repository https://ArtifexSoftware/aptest having secrets that allow the required access, and one should specify the corresponding environment variables using the --key option.
To create a github ReST token:
- Follow instructions for creating a "classic" token at
- https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-personal-access-token-classic.
- In
scopes, select justrepo.
If running as a Github action (GITHUB_ACTIONS==true), we add the
Aptest github repository secrets ARTIFEX_SOFTWARE_SSH_KEY and
PYMUPDFPRO_SETUP_SOT_KEY as keys for use with git operations on Github and
Gitlab.
Also see:
The gnn-download command downloads/extracts the DocLayNet dataset as described in https://github.com/ArtifexSoftware/sce/wiki/How-to-train-GNN.
- Downloading and extracting is tracked using marker files, to avoid running unnecessarily more than once.
- The test-gnn command runs
pymupdf_layouttests on the DocLayNet dataset, depending on the --test-gnn-det value. - The
pymupdf_layoutpackage must have been built/installed.
Aptest has support for customised bash argument completion using <tab>.
Activate in the current bash session with:
source <(aptest/aptest.py completion)
Alternatively activate in all new bash sessions with one of:
aptest/aptest.py completion > /etc/bash_completion.d/aptest.py.bash_completion aptest/aptest.py completion >> ~/.bash_completion
- Also see special command completion.
- 15.1 Overview
- 15.2 Commands
- 15.3 Options
- -a <env_name>
- -b <build-packages-modify>
- -e <name>=<value>
- --git-remote-modify <prefix> <replacement>
- -h
- -i <package-name> <package-location>
- --log-prefix <log_prefix>
- -m <mupdf-location>
- -o <os_names>
- -p <pymupdf-location>
- -r <remote>
- -t <test-packages-modify>
- -u (bool)
- -v <venv>
- -V <verbose>
- --atexit <command>
- --build-pip-no-clean (bool)
- --build-type debug | memento | release
- --check-pushed (bool)
- --check-unchanged (bool)
- --cibw-ignore-test-failures (bool)
- --cibw-name <cibw_name>
- --cibw-pyodide (bool)
- --cibw-pyodide-version <cibw_pyodide_version>
- --cibw-skip-add-defaults (bool)
- --clean-git <packages>
- --clean-setup <packages>
- --clean-setup-all <packages>
- --clean-wheelhouse (bool)
- --devel (bool)
- --draft-location <remote>
- --git-depth <depth>
- --git-local-detailed (bool)
- --gnn-doit (bool)
- --gnn-show-graph <path>
- --gnn-show-path <path>
- --gnn-show-select <expression>
- --gnn-show-text <path>
- --graal (bool)
- --help
- --key <prefix> <path>[,<env>]
- --langchain <langchain-pymupdf-layout-location>
- --langchain-pymupdf-layout <langchain-pymupdf-layout-location>
- --layout <pymupdf_layout-location>
- --mupdf <mupdf-location>
- --marina <smartoffice-marina-location>
- --neoso <smartoffice-neo-location>
- --pdf2docx <pdf2docx-location>
- --pdf_feature_inspector <pdf_feature_inspector-location>
- --pfi <pdf_feature_inspector-location>
- --pro <pymupdfpro-location>
- --pymupdf <pymupdf-location>
- --pymupdfpro <pymupdfpro-location>
- --pymupdf4llm <pymupdf4llm-location>
- --pymupdf_layout <pymupdf_layout-location>
- --pytest <pytest-flags>
- --pytest-junit-xml: (bool)
- --pytest-path <pytest_path>
- --pytest-timeout <timeout-secs>
- --pytest-timeout-method <method>
- --pytest-wrap gdb | valgrind | helgrind
- --python <python>
- --release-1
- --release-2
- --release-3
- --release-4
- --release-5
- --release-6
- --remote-do (bool)
- --remote-github-runners <github-runners-modify>
- --remote-github-workflow-id <workflow_id>
- --remote-github-yml <yml>
- --remote-github-yml-inputs <inputs>
- --remote-prefix <remote_prefix>
- --remote-prefix-default <remote> <prefix>
- --remote-rsync-path <remote_rsync_path>
- --remote-rsync-wsl (bool)
- --run <package> <command>
- --sdists (bool)
- --set-swig <swig>
- --set-swig-quick (bool)
- --smartoffice <smartoffice-location>
- --smartoffice-marina <smartoffice-marina-location>
- --smartoffice-neo <smartoffice-neo-location>
- --sot <smartoffice-location>
- --sot-neo <smartoffice-neo-location>
- --system-packages (bool)
- --system-site-packages (bool)
- --tee-auto (bool)
- --tee-path <path>
- --test-extra-packages <names>
- --test-gnn-cache (bool)
- --test-gnn-det <gnn_det>
- --test-gnn-extra <key>=<value>
- --test-gnn-limit <limit>
- --test-gnn-out <path>
- --test-gnn-push (bool)
- --ticker <delay>
- --use-release-args (bool)
- --venv-name <venv_name>
- --wheelhouse <wheelhouse_dir>
- --wheelhouse-release <wheelhouse_release>
- --4llm <location>
- 15.4 Special arguments
- Command line arguments are called options if they start with
-, otherwise they are called commands. - Options are evaluated first in the order that they were specified.
- Then commands are run in the order in which they were specified.
- Usually command test would be specified after commands such as build.
- Options and commands can be interleaved but it may be clearer to separate them on the command line.
Option values can be specified with --foo <value> or --foo=<value>.
Bool options are handled specially, they set to true by default, and can be
set explicitly using --foo=<value>:
Set to true:
--foo--foo=1--foo=true--foo=True
Set to false:
--foo=0--foo=false--foo=False
If this file exists, its contents are inserted before the command-line arguments.
- The tilde is expanded with
os.path.expanduser(), so on Windows this could beC:/Users/<username>/.aptest. - The file is ignored if the environment has
APTEST_DOT_APTEST=0.
The contents are extracted as follows:
- Lines starting with
#are ignored. - Arguments are extracted using shlex.split(), so are separated by whitespace (e.g. space and newlines characters) unless escaped or inside quotes etc.
If environmental variable $APTEST_options is set, it is added to the
command line after any ~/.aptest and before the command-line arguments.
- Arguments are extracted using shlex.split().
Builds and installs packages specified by -i into venv. Wheels are placed in
aptest-wheelhouse.Also see:
Build and test packages using cibuildwheel. Wheels are placed in directory
aptest-wheelhouse.
- We do not install wheels and it is generally not useful to do
cibw test.If
CIBW_BUILDis unset:
- On Github we set
CIBW_BUILDto build and test with all supported Python versions.- Otherwise we set
CIBW_BUILDto build and test with the current Python version only.If
CIBW_BUILDisall:
- We set CIBW_BUILD to build and test with all supported Python versions.
If
CIBW_ARCHSis unset:
- We set
CIBW_ARCHS_WINDOWS,CIBW_ARCHS_MACOSandCIBW_ARCHS_LINUXtoauto64if they are unset.cibuildwheel cannot handle pure python packages, so we manually build+test such packages.
- This will use the current python version only, and not (for example) a manylinux docker on Linux.
- For example with the pure-python package
pymupdf4llm, we only testpymupdf4llm+pymupdf_layout+pymupdftogether on native Python.- Unlike the build and test commands, cibw requires that packages have compatible version numbers, otherwise it will fail.
- It's non-trivial to support incompatible version numbers with cibuildwheel.
- cibw is generally used to build releases, for which version numbers should match anyway.
Also see:
Convert README.rst into README.rst.html.
Currently uses docutils.
Rsync the wheelhouse directory to the location specified by --draft-location.
The wheelhouse will contain a
simple/directory created bypiprepo, so one can pip install with:
pip install --extra-index-url ``<url>/simple.where
<url>is the URL of the draft location.We will also sync a piprepo subdirectory
simple/that willAlso see:
Download and extract dataset for the pymupdf_layout GNN model. Does not
do unnecessary downloads or extracts.
Generate graph showing results from previous runs of test-gnn.
For example:
aptest/aptest.py gnn-show --gnn-show-select \ " \ 'environ' in results \ and results['environ']['USER']=='jules' \ and results['python']['platform.system()']=='Windows' \ and results['state'].get('limit')==5 \ "Also see:
Trains pymupdf_layout. Not tested.
For packages specified with
git:..., populate local checkouts like the build command, but do not actually build/install anything.Packages are also cleaned if specified.
Also see:
Runs commands specified by --run within checkouts.
Runs pytest tests.
Also see:
- Test GNN model
- Writes results to
test-gnn-results/test-gnn-YYYY-mm-dd-HH-MM-SS.json.- Requires --test-gnn-det.
Results are a dict with this structure:
results['python']- Values from python's platform and sys modules.
results['environ']- Selected items from Python's os.environ.
results['state']- Description of what values we passed to
pymupdf_layout:eval/eval_util.py:evaluate_detection().results['packages']- Information about each package that we built/installed - version, git branch, sha etc.
results['pip-list']- Information from
pip listshowing information about all packages.results['results']- The results from the test.
results['t_duration']- Duration of test in seconds.
results['t_start']- Unix start time.
Also see:
Upload all wheels and sdists in directory specified by --wheelhouse-release, to https://pypi.org.
Show available Visual Studio installs.
Read next space-separated argument(s) from environmental variable
<env_name>.
- Does nothing if
<env_name>is unset.- Useful when running via Github action.
Comma-separated ordered list of modifications to the list of packages built and installed by the build command.
This list defaults to all packages specified by -i. Then for each comma-separated item in
<build-packages-modify>:
-<name>: removes package<name>from the list.+<name>and<name>: adds package<name>to the list.-removes all packages from the list.In addition if the first item does not start with
+or-we first remove all packages from the list.We allow aliases for package names.
For example:
Build only pymupdfpro:
-b -,P -b -,pymudfproRemove mupdf and layout from list of packages to build:
-b -m,--layout -b -mupdf,-pymupdf_layoutIf 'mupdf' was specified as a package but has been removed here, we set
PYMUPDF_SETUP_MUPDF_REBUILD=0so pymupdf will not rebuild its mupdf.
Set specified environment variable.
When cloning/fetching from git remotes, replace <prefix> with <replacement>.
For example:
--git-remote-modify git@github.com: https://github.com/Also see:
- -i.
Show this help.
Also see:
Add an input package.
package-name:One of:
aptest langchain_pymupdf_layout mupdf pdf2docx pdf_feature_inspector pymupdf pymupdf4llm pymupdf_layout pymupdfpro smartoffice smartoffice-marina smartoffice-neo(or their aliases.)
package-locationshould be one of:
"git:[-b|--branch <branch>] [--depth <depth>] [-s|--sha <40-char-sha>] [-t|--tag <tag>] [<remote>]"Clone/update from git remote into local checkout
aptest-git-<package-name>, from which we build/install from source.
- If the local checkout already exists, any local changes are deleted.
<remote>can also be a local checkout, from which Aptest will clone/fetch in the usual way.- A suffix can be appended to the local checkout name if --git-local-detailed is specified.
Defaults:
<branch>: hard-coded for each package (typically "master" or "main").<remote>: hard-coded for each package (typically a Github repository).<depth>: 1.pip:- Install from https://pypi.org using pip.
pip:*.tar.gz- Install from local sdist using pip.
pip:*.whl- Install from local wheel using pip.
pip:<suffix>- Install
<package-name><suffix>from https://pypi.org using pip. For examplepip:==1.26.3will install version 1.26.3 of the package.<directory>- A local directory, typically a git checkout, from which we build/install from source.
Separate locations for building and testing
If a package is specified twice, the first location will be used for building, and the second location used for testing. This allows packages on https://pypi.org to be tested, for example:
aptest.py -i pymupdf pip: -i pymupdf PyMuPDF build test- Test current pymupdf release with testsuite in
PyMuPDF/tests.aptest.py -i pymupdf pip: -i pymupdf git: build test- Test current pymupdf release with testsuite in current git.
Using upper-case package names
If a package is specified using an upper-case name, the package location is stored in a separate list that is only used if --use-release-args is specified. This is typically used in ~/.aptest to simplify making releases.
Aliases
Various convenience options and shortened aliases are provided:
- --langchain-pymupdf-layout and alias --langchain.
- --mupdf and alias -m.
- --pdf2docx.
- --pdf_feature_inspector and alias --pfi.
- --pymupdf4llm and alias --4llm.
- --pymupdf and alias -p .
- --pymupdf_layout and alias --layout.
- --pymupdfpro and alias --pro.
- --smartoffice and alias --sot.
- --smartoffice-neo and aliases --sot-neo, --neoso.
Also see:
Add prefix to all logging.
Specify location of package
mupdf.Alias for
-i mupdf <location>.Also see:
Control which OS's we run on. If current OS is not in (comma-separated) list
<os_names>, we do nothing.<os_names>is case insensitive, and items should matchlinux,windowsordarwin.Also see:
- --remote-github-runners - this will be more efficient when running on Github with -r @github.
Specify location of package
pymupdf.Alias for
-i pymupdf <location>.Also see:
Run ourselves on remote machine(s) and on success copy wheels back to local machine.
If
<remote>is@github, we run on Github:
We push specified local checkouts directories (specified by
-i,-m,-petc) to branches calledaptest-$USERin the hard-coded per-packagae central repositories, typically on https://github.com.If there are uncommitted changes they are temporarily committed and we use the git stash to save/restore things. As of 2026-03-30 this fixes a problem where newly-added files were removed.
We re-run the
aptest.pycommand on Github machines, changing-i,-metc args to usegit:...to refer to the above repositories.On success we copy Github logs and artifacts and extracted wheels etc to local directory:
gh_workflow_YYYY-mm-dd-<workflowid>Wheels are also copied in flat format into:
gh_workflow_YYYY-mm-dd-<workflowid>-union/.
-r@githubis ignored if we are already running on Github (GITHUB_ACTIONS=='true').Also see:
Otherwise
<remote>should specify a remote machine on which to run Aptest:
If
<remote>contains one or more spaces it is interpreted as the ssh command to use, optionally ending with a colon followed by the remote directory to use.For example:
-r 'ssh -p 2222 -J barfoo@mygateway foobar@mymachine.com:testdir'Otherwise
<remote>should be an rsync-style specification such asmacminiorusername@macmini:testdir.Specify a ssh jump host using
::, for example:-r <gateway>::<remote-host>Local checkouts specified by
-iare copied to the remote using rsync, thengit clean -fis run on the remote.The
aptest/directory is copied to the remote, using rsync.The
aptest.pycommand (without the-r ...arguments) is run on the remote machine.On success:
- Wheels are copied back into local directory
aptest-wheelhouse/.- test-gnn results directory
test-gnn-results/is synced to local machine.Also see:
Comma-separated ordered list of modifications to the list of packages tested by the test command.
This list defaults to all packages specified by -i or its aliases.
For each comma-separated item in
<packages>:
-<name>removes package<name>from the list.+<name>and<name>adds package<name>to the list.-removes all packages from the list.In addition if the first item does not start with +` or
-we first remove all packages from the list.We allow aliases for package names.
For example these test only pymupdfpro:
-t -,pro -t -,pymudfpro -t proAnd these remove
mupdfandlayoutfrom the list of packages to test:-t -m,--layout -t -mupdf,-pymupdf_layout
[Obsolete]
If true and -r @github is used, then on success we ask the user to confirm and then upload wheels to https://pypi.org.
This option is unsupported at present due to switching to the external ``pipcl`` package. However the information below about the name of the venv and convenience link still applies.
Changes how we re-run ourselves in a venv when required.
0 - Never re-run inside a venv.
For example one could use this if already in a venv.
- 1 - Use a venv but without recreating it if the directory already exists.
We assume any existing directory was created by us earlier and is a valid venv containing all necessary packages; this saves a little time.
Otherwise we create it with
python -m venv ....- 2 - (This is the default) Use a venv.
- Always (re)create it with
python -m venv ....- 3 - Use a clean venv.
- Delete it if it already exists, then run
python -m venv ....The venv will be called
venv-aptest-<pthonversion>-<wordsize>, for examplevenv-aptest-3.13.5-64.We also create a convenience link called
venv-aptest.Also see:
Set verbose level. Supported values are 0 and 1.
Run
<command>when Aptest terminates.For example:
--atexit 'printf "\\a"'--atexit beep
With command build, run
pip wheelwith--no-clean.According to
man pip wheel, this can also be done by setting environment variablePIP_NO_CLEAN.
Set build type. Default is release.
If true, fail if local checkout is not pushed to remote.
If true, fail if git diff is not empty in local checkout.
If true, the cibw command ignores test failures. Default is false.
Name to use when installing
cibuildwheelfor the cibw command, e.g.:--cibw-name cibuildwheel==3.0.0b1 --cibw-name git+https://github.com/pypa/cibuildwheelDefault is
cibuildwheel, i.e. the current release.
Make the cibw command build a pyodide wheel; runs
cibuildwheel --platform pyodide ... etc.
Override default Pyodide version to use with cibw command
by setting CIBW_PYODIDE_VERSION.
If true (the default) we add defaults to
CIBW_SKIPsuch aspp*(to exclude pypy) andcp3??t-*(to exclude free-threading), which effects the cibw command.Set to false with
--cibw-skip-add-defaults=0or--cibw-skip-add-defaults=falseor--cibw-skip-add-defaults=False.
Add comma-separated packages/aliases to list of packages for which we run
git clean -fdx in the build and populate commands.
Add comma-separated packages/aliases to list of packages for which we run
setup.py cleanin the build and populate commands.
- As of 2026-02-10, only pymupdf does anything in response to this.
pymupdf'ssetup.py cleandeletes files for pymupdf's extension and mupdf's C++/Python APIs.
--clean-setup pymupdfcan be useful if pymupdf fails to import mupdf; this can be caused by the build system not rebuilding correctly.
Add comma-separated packages/aliases to list of packages for which we run
setup.py clean --allin the build and populate commands.
- As of 2026-02-10, only pymupdf does anything in response to this.
pymupdf'ssetup.py clean --alldeletes files for pymupdf's extension and mupdf's C++/Python APIs and the mupdf C API.
If not specified (the default), then we first delete
aptest-wheelhouse/if we are doing a build of all specified packages.I.e. we delete
aptest-wheelhouse/if:
- Commands build or cibw are specified.
- And we are not skipping the build of one or more packages (with -b).
This is a useful default because it allows one to test while skipping slow rebuilds using -b, but still start with a clean wheelhouse in the usual case where everything is being built.
Otherwise:
- If true, we delete
aptest-wheelhouse/.- If false, we do not delete
aptest-wheelhouse/.
If true, output extra information, including:
- File/line information in log messages.
- Backtraces in error messages.
Location to which the draft command rsync's from the local wheelhouse.
If
<remote>can be accessed via https, it can be used as a pypi-style package repository with:pip install --extra-index-url <url>/simple ...For example after:
draft --draft-location julian@ghostscript.com:public_html/wheels-1.27.2One can install packages with:
pip install --extra-index-url https://ghostscript.com/~julian/wheels-1.27.2/simple pymupdf ...[Note the trailing
/simple.]
Set git depth when cloning/updating package specified with
git:....Also see:
- -i.
Default is false.
If true, we include any branch/tag/remote specification in local git clone path with
git:....For example with
--git-local-detailed -m=git:-b 1.27.x, the local directory will beaptest-git-mupdf--b_1.27.x.Also see:
- -i.
If 0 (the default) we never download/extract DocLayNet.
Override default name of gnn-graph out file in gnn-show command.
Add comma-separated paths of json output file for gnn-show command. Can be called multiple times.
Specify expression to use to select which
test-gnn-*.jsonfiles to include in output created by command gnn-show.
<expression>should be a Python expression that looks at Python dictresults.
<results>will actually be adoct.Doct()so dotted notation can also be used for keys that are legal Python identifiers.Example:
--gnn-show-select "'environ' in results and results.environ.USER=='jules' and results.python['platform.system()']=='Windows' and results.state.get('limit')==5
Override default filename of gnn-show text output.
If true we use Graal environment.
As of 2025-08-04, if true:
- We assert-fail if both cibw and non-cibw commands are specified.
- If the cibw command is specified:
- We use a conventional venv.
- We set
CIBW_ENABLE=graalpy.- We set
CIBW_BUILD = 'gp*'.- Otherwise we:
- Don't create a conventional venv.
- Clone the latest pyenv and build it.
- Use pyenv to install graalpy.
- Use graalpy to create venv.
[After the first time, suggest
-v 1to avoid delay from updating/building pyenv and recreating the graal venv.]
Show this help.
Also see:
- -h.
Specify a key file and/or environment variable, to be used for matching URLs or git remotes etc.
- The longest matching prefix is used.
- A match is only made if
<prefix>or<env>exist.<path>is the path of a file containing the key.<env>is the name of an environment variable containing the key.For example:
Use file
thirdparty-so-keyfor accessing git remotes starting withgit@gitlab.artifex.com::
--key git@gitlab.artifex.com: thirdparty-so-key.Also specify an environment variable for a Github repository secret, that allows access to gitlab when running in a Github action.
--key git@gitlab.artifex.com: thirdparty-so-key,PYMUPDFPRO_SETUP_SOT_KEYSpecify a file containing the pypi.org token to be used by the upload command:
--key https://upload.pypi.org/ token-pypi.orgIt can be convenient to put --key options in ~/.aptest, for example:
# Key for pypi.org for use by `upload` command. --key https://upload.pypi.org/ token-pypi.org # Key for Github ReST operations used by `-r @github`. --key https://api.github.com/ token-github.com # Key for accessing repositories on Github. --key git@github.com: artifex-software-ssh-key,ARTIFEX_SOFTWARE_SSH_KEY # Key for accessing repositories on Artifex Gitlab. --key git@gitlab.artifex.com: thirdparty-so-key,PYMUPDFPRO_SETUP_SOT_KEY
- When keys are used for ssh operations, Aptest runs ssh with
StrictHostKeyChecking=no, which may end up writing to~/.ssh/known_hosts.Also see:
Specify location of package
langchain-pymupdf-layout.Alias for
-i langchain_pymupdf_layout <langchain-pymupdf-layout-location>.Also see:
Specify location of package
langchain-pymupdf-layout.Alias for
-i langchain_pymupdf_layout <langchain-pymupdf-layout-location>.Also see:
Specify location of package
pymupdf_layout.Alias for
-i pymupdf_layout <pymupdf_layout-location>.Also see:
Specify location of package
mupdf.Alias for
-i mupdf <mupdf-location>.Also see:
Specify location of package
smartoffice-marina.Alias for
-i smartoffice-marina <smartoffice-marina-location>.Also see:
Specify location of package
smartoffice-neo.Alias for
-i smartoffice-neo <smartoffice-neo-location>.Also see:
Specify location of package
pdf2docx.Alias for
-i pdf2docx <pdf2docx-location>.Also see:
- -i.
Specify location of package
pdf_feature_inspector.Alias for
-i pdf_feature_inspector <pdf_feature_inspector-location>.Also see:
Specify location of package
pdf_feature_inspector.Alias for
-i pdf_feature_inspector <pdf_feature_inspector-location>.Also see:
Specify location of package
pymupdfpro.Alias for
-i pymupdfpro <pymupdfpro-location>.Also see:
Specify location of package
pymupdf.Alias for
-i pymupdf <pymupdf-location>.Also see:
Specify location of package
pymupdfpro.Alias for
-i pymupdfpro <pymupdfpro-location>.Also see:
Specify location of package
pymupdf4llm.Alias for
-i pymupdf4llm <pymupdf4llm-location>.Also see:
Specify location of package
pymupdf_layout.Alias for
-i pymupdf_layout <pymupdf_layout-location>.Also see:
Specify extra pytest flags when Aptest runs
pytest.Used by the test and cibw commands.
For example:
--pytest '-k test_123'--pytest '-v -k "test_123 or test_246"'
Runpytestwith--junit-xmland write info intoaptest-wheelhouse.
Specify a directory/file/test-function to be used by pytest with the test and cibw commands, relative to each project root directory.
Can be specified multiple times. Default is
<package_root>/tests/.
Install pytest-timeout and run pytest with
--timeout <timeout-secs>.
- Note that this does not interrupt extension code.
Run pytest with --method <method> (requires --pytest-timeout).
Makes test command run pytest under specified tool.
Set Python to use. If set we re-run ourselves using specified python command.
Build release wheels for
pymupdf,pymupdfpro,pymupdf4llmandpymupdf_layout, for core platformslinux-x64,windows-x64andmacos-arm64.Also builds sdists.
Also see Release procedure.
Build release wheels for
pymupdf,pymupdfpro,pymupdf4llmandpymupdf_layout, for platformslinux-aarch64andmacos-x64.Also see Release procedure.
Build release
pymupdfwheel for platformwindows-x32.Also see Release procedure.
Build release
pymupdfwheel for platformlinux-x64-musl.Also see Release procedure.
Build release
pymupdfwheel for platformpyodide.Also see Release procedure.
Build release
pymupdfwheel for platformlinux-x64and free threading python-3.14.Also see Release procedure.
[For debugging.]
Default is true.
If false (
--remote-do=0) we don't sync to remote and we don't run any commands on remote. But we do sync remote wheels to local.
Comma-separated ordered list of modifications to the list of Github runners on which -r @github runs.
This list defaults to runners for Linux-x64, Windows-x64 and MacOS-arm64. Then for each comma-separated item in
<github-runners-modify>:
-<name>: removes runner<name>from the list.+<name>and<name>: adds runner<name>to the list.-removes all runners from the list.In addition if the first item does not start with
+or-we first remove all runners from the list.We allow aliases for Github runners names:
linux,linux-intel.macos-intel.macos,macos-arm.windows-arm.windows,windows-intel.For example:
Run only on windows-arm:
--remote-github-os windows-arm --remote-github-os -,+windows-arm
Changes the behaviour of -r @github. Don't start a new run on Github, instead continue from a previous -r @github invocation by waiting for
<workflow_id>to finish and downloading logs and wheels etc to the local machine.
- One still needs to specify -r @github.
Previous downloads are not repeated unnecessarily:
- Downloads are made to a temporary file that is then atomically renamed.
- Files that already exist locally are not downloaded again.
With -r @github, run the specified.ymlfile (leafname only) instead of runningaptest.py. If no packages are specified, runs on Github'sArtifexSoftware/aptestrepository; otherwise exactly one package must be specified.
Specify inputs used with --remote-github-yml.
<inputs>should be a comma-separated list of<name>=<value>pairs.For example if the .yml file has:
on: workflow_dispatch: inputs: args: type: string default: '' description: 'Arguments to pass to aptest.py'Then:
--remote-github-yml-inputs 'args=-o windows'
Run remote using specified (Python) command. Ignored by -r @github.
Sets default remote prefix for a specific remote when specified with
-r <remote>. For example to always use python-3.12 on remote machinejules-asus, use:--remote-prefix-default jules-asus python312Also see ~/.aptest.
Specify--rsync-pathwhen running rsync, to identify location of rsync on remote. E.g.--remote-rsync-path 'wsl rsync'if remote is a Windows machine with rsync installed in the default WSL system.
[Experimental.]
If true we tweak various things to cope with remote using wsl rsync.
Make run command run the specified command within checkout of
<package>.
If true, the build and cibw commands will also build sdists.
We only build sdists for these packages:
pymupdfpymupdf4llmpdf2docxWith cibw, we only build sdists if on Linux.
Specify what swig to use.
If
pip:...we install using pip.(Unix only) If
git:...we clone/update/build swig from a git repository.We default to https://github.com/swig/swig.git branch master, so these are all equivalent:
--set-swig 'git:--branch master https://github.com/swig/swig.git' --set-swig 'git:--branch master' --set-swig git:Otherwise should be the swig binary to use.
If true and --set-swig's<swig>value starts withgit:, we do not update/build swig if it is already present.
Specify location of package
smartoffice.Alias for
-i smartoffice <smartoffice-location>.Also see:
Specify location of package
smartoffice-marina, an alternative to--smartoffice.Alias for
-i smartoffice-marina <smartoffice-marina-location>.Also see:
Specify location of package
smartoffice-neo, an alternative to--smartoffice.Alias for
-i smartoffice-neo <smartoffice-neo-location>.Also see:
Specify location of package
smartoffice.Alias for
-i smartoffice <smartoffice-location>.Also see:
Specify location of package
smartoffice-neo.Alias for
-i smartoffice-neo <smartoffice-neo-location>.Also see:
If true, automatically install required system packages such as Valgrind, usingapton Linux andbrewon MacOS. Default is true if running as Github action, otherwise false.
If true, use --system-site-packages when creating venv. Defaults is false.
If true, we copy log output to file
aptest-out-YYYY-mm-dd-HH-MM-SS, and on exit create convenience softlinkaptest-out.Otherwise we cancel any existing tee.
If -r is used to run on a remote machine (not
@github`), we create a second convenience softlink called ``aptest-out-<remote>.Default is false.
Can be useful to put this in ~/.aptest.
Copy log output to file
<path>.Can be useful to put this in ~/.aptest.
Installs specified comma-separated packages from https://pypi.org before running tests in test command.
If true,
test-gnn*commands look for a matchingtest-gnn-*.jsonfile. If one is found, we do not run, instead creating softlinks to the matching.jsonfile.To match, we require all fields in a
.jsonfile match the file that we would create for the current run, except for:
['results']- not available for the current run, obviously.['t_start']['t_duration']['pip-list']- we allow changes to misc other packages, e.g. version numbers may vary.We require the other settings to be identical, such as:
- OS, machine name, username etc.
- Python version, implementation etc.
- How Artifex packages were specified, e.g.
-p git:or-p pip:.- git sha's and diffs for Artifex packages specified with
git:or local checkout.- https://pypi.org version numbers for Artifex packages specified with
pip:....- Any --test-gnn-limit value.
This is required by test-gnn.
Sets the Python script to be run, relative to the root of the
pymupdf_layoutcheckout.Valid values for
<gnn_det>are:
eval/eval_docling.pyeval/eval_gnn.pyeval/eval_oracle_gnn.pyeval/eval_pymupdf4llm.pyeval/eval_pymupdf_layout.py
Adds specified key=value pair to the root of the results dict
created by test-gnn.
Set number of gnn files to tested by test-gnn. Default is all.
Where to write json data containing test details from test-gnn. Default is a filename containing the current date and time.
If true, we push gnn results from test-gnn to https://github.com/ArtifexSoftware/PyMuPDF-pymupdf-results. Default is false.
Use ticker with specified delay. Disabled if delay==0. Default is
0.5.
- Use upper-case package locations (see -i's upper-case-package names section), typically specified in ~/.aptest.
- Require that --wheelhouse-release has been specified, and use its value for the wheelhouse.
- The new value must be different from the default wheelhouse, so that we can protect against non-release builds deleting a partially complete release procedure.
- We never remove the contents of this wheelhouse, because multiple invocations of Aptest are required to build the release wheels. So --clean-wheelhouse is ignored.
Also see:
Sets the venv name used by -v.
Default is
venv-aptest-<python-version>-<word-size>, for examplevenv-aptest-3.14.2-64.
Directory in which to place wheels, instead of default
aptest-wheelhouse.Also see:
Directory in which to place wheels when building releases.
Also see:
Specify location of package
pymupdf4llm.Alias for
-i pymupdf4llm <location>.Also see:
Must be the only arg. Writes an Aptest bash completion script to stdout.
The completion script works by internally running
aptest.pyin completion mode (whereCOMP_LINEis defined), where it writes valid completions to stdout.When in completion mode, Aptest will append diagnostics to file
APTEST_COMPLETION_DEBUGif defined.Also see Argument completion with Bash.
2026-06-24
- In
.github/workflows/test_release.yml, temporarily use mupdf-1.28.x until there is a mupdf 1.28.0 tag. - Fixed key handling for pymupdfpro and marina.
2026-06-22
- Fixed
.github/workflows/test_release.yml.
2026-06-19
- Added AGPL-3.0-only license - see License.
- Updated Github workflow to test mupdf-1.28.x branch.
2026-06-18
- Added section on creating/using development wheels, Making internal development releases.
- Don't delete wheelhouse if it contains a file called
_aptest_wheelhouse_preserve. - Improved use of
piprepoto create pypi-style database in wheelhouse:- Remove all wheels that are unknown to Aptest.
- Recreate pypi-style database before uploading with draft.
- Recreate pypi-style database before exiting.
- Minor improvements to output from autoenv on startup.
- Modify .github/workflows/test_multiple.yml to match pymupdfpro now defaulting to marina.
- Show current directory on startup.
- With upload, also upload pyodide wheels to pypi, which now accepts them.
2026-06-15
- Simplified where we put wheels:
- Removed
--wheelhouse-union. - Removed
--wheelhouse-union-release. - Added --wheelhouse-release.
- When building on Github, download wheels into our wheelhouse.
- Removed
- Various fixes to --release-*.
- Improved display of args - show
~.aptest,APTEST_optionsand command line separately.
2026-06-14
- Further fix of
.github/workflows/test_multiple.ymlartifact names.
2026-06-12
- Write command line to log output on startup.
- In
.github/workflows/test_multiple.yml, fix creation of artifacts containing wheels.
2026-06-10
Fix Windows builds with cibw by disabling wheel repair with
CIBW_REPAIR_WHEEL_COMMAND_WINDOWS=''.(This is because
cibuildwheelhas started to usedelvewheel, which apparently cannot find ourmupdfcpp64.dll.)
2026-06-01
- Added --build-pip-no-clean, to preserve
pip wheelbuild directory. - Fixed detection of free-thread python.
- Show Aptest git info on startup.
- Change whether we clean wheelhouse; see --clean-wheelhouse.
- Don't run pytest with
--junit-xmlby default; see --pytest-junit-xml. - Added --git-local-detailed.
2026-05-14
- Improved handling of EOF on command line.
2026-05-10
- Updated test_multiple, we currently need to patch marina.
2026-05-07
- Fix --pytest-wrap.
2026-05-03
- More concise command-line diagnostics if ~/.aptest or $APTEST_options are used.
- If we fail to create softlink to venv, output warning instead of failing.
2026-04-31
- Fix bug if python executable path has spaces, e.g. on Windows.
- Fix incorrect warnings about directories not being a git checkout, e.g. with case changes on Windows or trailing slash.
2026-04-30
- Improved How to run Aptest, and added pipx examples.
- Improved pro/marina builds with cibw.
2026-04-27
- Improved Release procedure.
- Improved description of how to install aptest with pip; see How to run Aptest.
- Avoid unnecessary backtraces after some command line errors.
2026-04-23
- Improved diagnostics/backtraces on errors.
- Added --pytest-timeout and --pytest-timeout-method.
- Fix git errors in manylinux docker with cibw by setting
safe.directory. - Set correct ssh/git key if building
pymupdfprowithsmartoffice-marina. - Special-case
CIBW_BUILD=all; see cibw. - Default to deleting wheelhouse if build or cibw commands are specified; see --clean-wheelhouse.
- Control of venv with -v is currently unsupported.
2026-04-18
- Fixed building of pipcl.
- Fixed handling of PIP_EXTRA_INDEX_URL on manylinux.
- Avoid spurious differences between line endings in wheels when building on Windows.
2026-04-16
- Added --git-remote-modify.
- Added --wheelhouse.
- Fix --cibw-pyodide-version.
- Add support on Unix for building/installing as a Python package, providing console command
aptest.- Can still be used directly from a checkout.
- Uses pipcl package from pypi.org (have removed local pipcl.py and wdev.py).
2026-04-09
- When a package location is specified with
git:..., allow<remote>to be a local checkout. See -i.
2026-04-02
- Fixed bug in release builds.
- Document that the cibw command requires that package versions are compatible.
- Added --clean-wheelhouse.
2026-04-02
- Fix build of
pymupdfproon Github.
2026-04-01
- Fixed scheduled Github tests - use Aptest repository secrets for Github/Gitlab keys. See Default keys when running on Github.
2026-03-31
- Added control of git depth; see --git-depth.
- Improve internal specification of packages - use explicit git remote.
- With cibw, improve handling of old versions of pymupdf.
- Improved key handling, removing hard-coded key file paths in favour of new option --key.
- Added support for (pseudo) package
smartoffice-marinawith pymupdfpro. - Added pymupdf4llm to scheduled Github tests in
.github/workflows/test_multiple.yml. - Ignore -r @github if already running on Github.
- Fixed -r @github forgetting about newly added files.
- Removed
--4llm-unifiedas we decided not to unifypymupdf4llmandpymupdf_layout. - Make
--tee-auto=0cancel an existing tee.
2026-03-20
- Fix use of --smartoffice with cibw.
2026-03-19
Fix handling of
pdf4llmwheels when making releases.(Like
pymupdf4llmwheels, these are pure python but differ if created on Windows due to carriage return characters.)Minor improvements to diagnostics.
2026-03-18
- Added
pymupdf4llmandpdf4llmto Release procedure. - With cibw, don't build/test
pymupdf4llmandpdf4llmon macos/intel/python-3.14, becauseonnxruntimenot available. - Added --check-pushed.
2026-03-17
- Added
pymupdf4llmandpdf4llmto.github/workflows/test_release.yml. - Add handling of --check-unchanged when running on Github.
- Don't install extra packages when testing
pymupdf4llm- is now unnecessary.
2026-03-16
- Added support for pdf4llm.
- Add pdf4llm to release.
2026-03-12
- Use Github's native linux-arm runner instead of CIBW_ARCHS_LINUX=aarch64 and emulation.
- Run pytest in 4llm's top-level tests/ directory, not test/pymupdf4llm/llama_index/.
- Create pretty-printed version of pytest's pytest-junit.xml.
2026-03-10
- Don't overwrite
--teeoutput when doing bash command completion. - Cope with windows pure python
pymupdf4llmwheels differing because of DOS line endings. - Improved release procedure.
- Build all wheels/sdists in local directory using multiple invocations of Aptest.
- Upload everything to https://pypi.org in one operation.
- New option --check-unchanged.
- New option --draft-location.
- New option --log-prefix.
- New option
--wheelhouse-union. - New option
--wheelhouse-union-release. - New command draft.
- New command upload.
2026-03-05
- Disabled backtraces in args diagnostics, unless --devel is specified.
- Fixed build ordering of
pymupdf_4llmbecause it now requirespymupdf_layout.
2026-03-04
- Avoid problems on Github caused by pytest searching for a pytest.ini file.
- With cibw, avoid extra prerequisite wheels for pure-python packages in aptest-wheelhouse.
2026-03-04
- Removed aliases
-l,-s,-P. - Internal fix to not use
|head -n 1withgit log -1. - Added --neoso alias for --smartoffice-neo.
2026-03-04
- Avoid git delays on Windows - use
git log -1instead ofgit show. - Added
smartoffice-neopackage, an alternative tosmartoffice. See --smartoffice-neo.
2026-03-04
- Renamed
--swigand--swig-quickto --set-swig and --set-swig-quick. - Added support for package
swig. - Changes to test-gnn.
--4llm-unifiednow expects layout to be in 4llm (previously 4llm was moved into layout).- Fixed handling of
pymupdf4llm. - Also build sdists for
pymupdf4llmandpdf2docx(as well aspymupdf). - Added pymupdf4llm to --release-1.
- Allow trailing / in local package checkout paths.
- Run
gitwith-no-pagerto attempt to avoid long delays on Windows.
2026-02-26
- Fixed build of
pymupdf-cp314twheel in --release-6 command. - Use stylesheet in docs command when producing README.rst.html.
2026-02-25
- With cibw command, support --pytest-path (was previously ignored).
- Fix --python.
- Generate junit .xml file when running pytest.
- Fix --clean-setup with pymupdf's mupdf.
- Avoid duplicate
aptest-out-*files when re-running ourselves in venv or on remote machine. - Add support for
pip:...to--swig. - Added --release-6 for python-3.14t (free threading) wheel.
- Added docs command.
2026-02-18
- New command line parser.
- Accepts
--foo=baras well as--foo bar. - Special case for Bool args:
- Bools are now specified as
--fooor--foo=<value>. - Previous
--foo <value>must be changed to--fooor--foo=<value>, for example in ~/.aptest and $APTEST_options.
- Bools are now specified as
- See Option values.
- Accepts
- Ignore ~/.aptest if
APTEST_DOT_APTEST=0. - Added new command windows-show-vs-instances.
- Allow control over what Github runners are used with
-r @github- see new option --remote-github-runners.
2026-02-12
- Added
--token-github-path. - Added
--token-pypi-path. - Fixed
-r @githubon Windows.
2026-02-11
- Fixed -u upload.
- Fixed checking of --release-* options.
- Fixed bug in run command.
2026-02-10
- Improved output after downloading from Github.
- Added --cibw-ignore-test-failures.
- Renamed
--log-teeto --tee-auto. - Added --tee-path.
- Added --atexit.
- Added support for
pdf2docx- see --pdf2docx.
2026-02-09
- Changed -V to take the verbose level (0 or 1) instead of incrementing it.
- Changed default verbose level to 1.
- Show git sha and diff of Aptest itself on startup if verbose.
- cibw: don't attempt to build/test layout on macos-intel-python3.14 because onnxruntime not available.
- Fixed .github/workflows/test_multiple.yml failures.
- Improved error diagnostics.
- Improved clean options.
2026-02-05
- Added --atexit
- Fix --smartoffice to use
thirdparty-so-key. - Optionally copy output to date-stamped file. See
--log-tee. - Improved sorting of options in
README.rst. - Improved handling of
-p pip:- we now setPYMUPDF_SETUP_VERSIONso other packages will match correctly. - Fix
--smartoffice git:on Github - usePYMUPDFPRO_SETUP_SOT_KEYif set. - Added test of pymupdfpro with latest smartoffice to Github tests.
- Fix -b and -t to do nothing if given empty string value.
- In
~/.aptest, ignore lines starting with#.
2026-01-31
- Update tests to use mupdf 1.27.x branch.
- Added experimental support for unified 4llm+layout package; see
--4llm-unified.
2026-01-30
- Allow testing of Aptest itself.
- Added --release-5 for building pyodide pymupdf wheel.
- Avoid remaining potential for
buildcommand to end up installing incorrect package versions.
2026-01-15
- Fix potentially incorrect package versions if
pip:is used. - Fix flake8 errors.
- Fix codespell errors.
- All docs are now in README.rst.