Release history
0.3.1
2026/06/07
Windows launcher build no longer breaks when the current directory is excluded
from the executable search path. The launcher build step now invokes the
generated batch file as .\build.bat instead of a bare build.bat. On
systems where NoDefaultCurrentDirectoryInExePath is set, cmd.exe does not
search the current directory for the script, so the previous form failed to find
it and the MSI build aborted during launcher compilation.
Quieter launcher compile. The Windows launcher C source now uses
_snwprintf_s (with _TRUNCATE) instead of the deprecated _snwprintf,
removing the MSVC C4996 warning while guaranteeing null-termination on
truncation.
0.3.0
2026/06/06
macOS .app / .dmg packages. Two new GUI formats build native macOS
bundles: format = "macapp" produces a .app bundle and format = "dmg"
wraps it in a disk image. A Mach-O launcher stub is compiled with clang, the
.app is assembled with an Info.plist and an icns icon, then
deep-codesigned (ad-hoc by default; Developer ID + hardened runtime when
signing-identity is set) and, with a notary-profile, notarized via
notarytool and stapled. These formats require the app-level identifier
(reverse-DNS CFBundleIdentifier) and build only on a macOS host.
Per-OS launcher icons. [[launchers]].icon is now a per-OS table —
icon = { windows = "*.ico", macos = "*.png", linux = "*.png" } (each key
optional; a plain string is rejected). This replaces the old single .ico and
the target-level macOS icon, so each launcher can carry its own icon per OS.
Opt-in MSI code signing. Set code-sign = true on an MSI target to sign
the launcher .exe and the .msi. The signing command is resolved with the
precedence PYAPPDIST_SIGN_CMD (env) > code-sign-command (config) > a
built-in signtool default. MSIX and the macOS .dmg keep their previous
environment-variable-only behavior.
Per-target extras. Each target may set an extras list selecting
[project.optional-dependencies] extras to bundle. The names are passed
through to the lockfile export using the manager’s own flag (uv --extra,
poetry --extras, pdm --group, pipenv --categories). The default is
empty (production dependencies only); extras are ignored with a warning in
requirements.txt mode.
python -m launcher entry. A launcher entry may now be a colon-less
dotted "module.path", run as python -m module.path
(runpy.run_module with __name__ == "__main__"), alongside the existing
"module:callable" form. This packages apps whose startup lives under an
if __name__ == "__main__": guard (e.g. NiceGUI) without modification.
Config keys are now kebab-case (breaking). All underscore-separated
[tool.pyappdist] keys were renamed to hyphenated form: upgrade-code,
code-sign, code-sign-command, identity-name, display-name,
min-macos, signing-identity, team-id, notary-profile. Update
existing pyproject.toml files accordingly.
Installer reports installed commands. The POSIX self-extracting .run
installer now lists the command names it symlinked into <prefix>/bin when it
finishes.
0.2.0
2026/06/03
Multiple output formats and targets. A project can now produce several
packages from one configuration. The single [tool.pyappdist.wix] table plus
a single target has been replaced by a [[tool.pyappdist.targets]] array,
where each entry is one output package with its own platform and format.
format is now required and is validated against the platform’s OS
(msi/msix for Windows, linux for Linux, macos for macOS), so a
mismatch is reported as a configuration error at load time instead of failing
mid-build.
MSIX output (Microsoft Store). A new format = "msix" produces an
unsigned, full-trust Win32 .msix package — emitting AppxManifest.xml
(one <Application> per launcher) and packing the image with makeappx.
The Store signs the package on ingestion; local installs require Developer Mode.
Linux packages. A new format = "linux" builds a real Linux distribution
using relocatable shell-wrapper launchers (no MSVC), and emits two artifacts: a
.tar.gz of the image tree and a self-extracting .run installer. The
installer is per-user (installs under $HOME/.local, no root and no FUSE),
symlinks launchers into bin, and writes a .desktop file for launchers
that declare an icon.
macOS packages. A new format = "macos" (platforms macos-aarch64 and
macos-x86_64) ships the same per-user tarball + self-extracting .run as
Linux, built on the matching macOS host. The default payload compression is
gzip (xz is not preinstalled on macOS), and — with no freedesktop
equivalent — launcher icon/gui are ignored, so the installer just
symlinks launchers into <prefix>/bin.
MSI install scope and licensing. Install scope is now a build-time
machine/user choice: scope = "user" (default; installs per-user under
%LocalAppData%\Programs) or scope = "machine" (Program Files). The MSI
license (EULA) is now optional, and per-user installs get a proper user-folder
redirect.
Internals. Runtime extraction now uses the tarfile "tar" filter, and
the runtime_source option was dropped.
Docs and samples. Per-format details are now documented as independent sections rather than notes; sample apps were translated to English; an end-to-end editable-install verification project was added; each output format now has its own documentation page; and design and migration notes for macOS support were added.