Skip to main content

kavacha

kavacha (कवच, “armour”) is for Python web apps that run on the user’s own machine, such as a FastHTML app that uvicorn serves on 127.0.0.1. It does two jobs. While the app runs, it opens a native desktop window that shows the app, so the user gets an application with its own Dock icon and menu bar instead of a browser tab. At build time, it turns the project into a standalone application that carries its own copy of Python, so the user does not have to install Python to run it.

The build side relies on a freezer. A freezer is a tool that collects a Python program, the interpreter and every module the program imports into one folder that runs by itself. kavacha uses py2app on macOS, where that folder is a .app bundle, and py2exe on Windows. Each freezer has to be told about imports it cannot find by reading the code, and each leaves problems behind in the bundle it writes. kavacha keeps the description of your app in one place, turns it into the options each freezer expects, and repairs the bundle afterwards.

Install

pip install kavacha

The base package depends only on fastcore, so you can describe an app and check a build on any machine, Linux included. Extras add what each job needs:

extra adds needed for
window pywebview, with pyobjc on macOS or pythonnet on Windows opening the native window
icons Pillow making icons from one image
macapp window, icons and py2app building a macOS app
windows window, icons and py2exe building a Windows app
pip install "kavacha[macapp]"

Describe the app

An App describes the application once, and both freezers take their options from it.

from kavacha import App, tree, doc_types, mypyc_modules

app = App(
    name='Demo',
    entry='demo_app.py',
    version='1.2.3',
    icon='assets/Demo.icns',
    packages=['demo', 'fasthtml', 'uvicorn', 'numpy'],
    includes=['demo.cli', *mypyc_modules()],
    grafted=['apsw', 'playwright'],
    data=tree('demo/static', 'demo/static'),
    extras=['desktop'],
    doc_types=doc_types(['.py', '.rs', '.md']),
)
app.py2app_options()

entry is the script the app runs. packages are copied into the bundle whole. includes names single modules the freezer would miss because no import statement names them, such as the compiled helper modules mypyc_modules finds. grafted names packages that do not work from inside the freezer’s zip archive, so kavacha copies them in after the freezer has run. data lists files the app reads that are not Python, and tree builds that list from a folder. doc_types declares which files Finder may open with the app. extras are the optional dependency groups of your project that the build environment installs. py2app_options() and py2exe_options() return the options for each freezer. The spec page covers every field.

Build

from kavacha import build, check

check(app, root)
build(app, root, setup_py='packaging/macos/setup.py')

check reports what a build would do on this machine without changing anything: which freezer it would use, whether the Python it runs on can be used, whether pywebview is installed, and whether a copy of the app is running. build then does the work. root is your project folder and setup_py is the script that calls the freezer.

On macOS, py2app can only embed a framework build of Python, the kind python.org and Homebrew install. The interpreters uv and pyenv download are not framework builds. When the current Python is not one, build finds one, creates a virtual environment from it with the package versions pinned in uv.lock, and runs your build script again inside it. It refuses to overwrite an app that is running unless you pass force=True, and it writes the git commit the app was built from into the bundle. The build page has the details.

After freezing

from kavacha import finish, sign

finish(bundle, app)
sign(bundle, 'Developer ID Application: ...', 'entitlements.plist')

py2app’s output needs some repairs before it runs well. finish makes them in order: it copies in the grafted packages, deletes the copies of them and any other unused code from the bundle’s zip archive, replaces identical large files with hardlinks, repairs libraries in Contents/Frameworks that py2app mixed up because two had the same file name, and installs a macOS 26 Icon Composer icon if the app has one. build calls finish for you on macOS, so you only call it yourself when you run the freezer some other way. sign code-signs the finished bundle. The bundle page explains each step.

Icons

from kavacha.icons import icons_for

icons_for('assets/logo.png', 'assets', 'Demo')

icons_for takes one square image at least 512 pixels wide and writes a PNG favicon for the web page, a Windows .ico and, on macOS, an .icns for the bundle. It refuses a smaller or non-square image instead of stretching it.

Window

from kavacha.window import run_shell, shell_ready, use_app

use_app('Demo')
ok, why = shell_ready()
run_shell(['http://127.0.0.1:8000/'], titles=['Demo'], size=(1440, 900))

shell_ready says whether this machine can open a native window and, if it cannot, what is missing. use_app sets the name kavacha uses for the window title and the settings folder. run_shell opens one window for each URL in the list, shows a holding page until the server at that URL answers, and then runs the platform’s GUI loop until the app quits. Start your server first, on another thread or process, and call run_shell on the main thread. The host, the application using kavacha, can also pass callbacks for opening folders and a menu bar built from the classes in kavacha.menus. The window page describes them.

Status

The spec, build, bundle and icon modules have tests that run on any platform. The window and menu code was moved here from an application where it is in daily use, but CI cannot open a macOS window, so it is not exercised here. Try it on a Mac before you depend on it.

Metadata

Release files for kavacha 0.0.10

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for kavacha 0.0.10
File Size Uploaded Provenance Actions
kavacha-0.0.10.tar.gz 32.2 kB Without provenance Details for kavacha-0.0.10.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for kavacha 0.0.10
File Interpreter ABI Platform Actions
kavacha-0.0.10-py3-none-any.whl Python 3 none any Details for kavacha-0.0.10-py3-none-any.whl

Total release size: 68.2 kB

Release files / kavacha-0.0.10.tar.gz

Download URL kavacha-0.0.10.tar.gz
Size 32.2 kB
Tags Source
SHA-256 checksum
How to use checksums
01309cc5221d42c6bb512129b8e916bbf99e4ad47ab59ad0be272481f8e45d40
BLAKE2b-256 checksum
How to use checksums
a2827744eabdaa9d560806ae63755fd6c9536f2c675821c6319104c0d0440f47
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Release files / kavacha-0.0.10-py3-none-any.whl

Download URL kavacha-0.0.10-py3-none-any.whl
Size 36.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6273cd9e5cd4365d65b7fbd478818f2bf38986e2998811dec0a814de4fa6dc85
BLAKE2b-256 checksum
How to use checksums
178a3b19cbd257c13e03f557709f60ed6cbea2ee175e88eec0eebf9b65dc551c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Security for kavacha 0.0.10

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page