Webview Python
Python bindings for the webview library, allowing you to create desktop applications with web technologies.
Production-Ready Applications
For enterprise-grade desktop applications, see the complete template:
python_desktop_app_with_vue_template
. This project provides a full solution for frontend-backend integration, development workflow, debugging, and deployment.
Alternative: WebUI
While developing the production template, I discovered
, which appears to be an earlier project than webview/webview (though I haven't verified this claim). WebUI might be worth investigating as an alternative, but I haven't had time to do a thorough comparison. If anyone has insights or experience with WebUI vs webview, I'd appreciate hearing from you.
Installation
pip install webview_pythonEnvironment Variables
Webview Python supports the following environment variables:
WEBVIEW_VERSION: Specify the version of the webview library to use (default: "0.9.0")
WEBVIEW_DOWNLOAD_BASE: Specify the base URL or file path for downloading webview libraries (default: GitHub releases) Can be a web URL: https://internal-server.com/webview-libs
Network share: \\server\share\webview-libs or /mnt/server/webview-libs
Local path: /path/to/libs or C:\path\to\libs
Example usage:
# Using an internal HTTP serverexport WEBVIEW_DOWNLOAD_BASE="http://internal-server.com/webview-libs"# Using a network share on Windowsset WEBVIEW_DOWNLOAD_BASE=\\\\server\\share\\webview-libs # Using a mounted path on Linuxexport WEBVIEW_DOWNLOAD_BASE="/mnt/server/webview-libs"Note: When using a custom download location, you must organize the libraries in the same structure as the GitHub releases:
WEBVIEW_DOWNLOAD_BASE/ ├── 0.9.0/ │ ├── webview.dll # Windows x64 │ ├── WebView2Loader.dll # Windows x64 │ ├── libwebview.x86_64.so # Linux x64 │ ├── libwebview.aarch64.so # Linux ARM64 │ ├── libwebview.x86_64.dylib # macOS x64 │ └── libwebview.aarch64.dylib # macOS ARM64 └── other-versions/... Usage
Display Inline HTML:
fromwebview.webviewimportWebviewfromurllib.parseimportquotehtml="""<html><body><h1>Hello from Python Webview!</h1></body></html>"""webview=Webview() webview.navigate(f"data:text/html,{quote(html)}") webview.run()Load Local HTML File:
fromwebview.webviewimportWebviewimportoswebview=Webview() current_dir=os.path.dirname(os.path.abspath(__file__)) html_path=os.path.join(current_dir, 'local.html') webview.navigate(f"file://{html_path}") webview.run()Load Remote URL:
fromwebview.webviewimportWebviewwebview=Webview() webview.navigate("https://www.python.org") webview.run()Python-JavaScript Bindings:
fromwebview.webviewimportWebview, Size, SizeHintfromurllib.parseimportquotewebview=Webview(debug=True) # Python functions that can be called from JavaScriptdefhello(): webview.eval("updateFromPython('Hello from Python!')") return"Hello from Python!"defadd(a, b): returna+b# Bind Python functionswebview.bind("hello", hello) webview.bind("add", add) # Configure windowwebview.title="Python-JavaScript Binding Demo"webview.size=Size(640, 480, SizeHint.FIXED) # Load HTML with JavaScripthtml="""<html><head> <title>Python-JavaScript Binding Demo</title> <script> async function callPython() { const result = await hello(); document.getElementById('result').innerHTML = result; } async function callPythonWithArgs() { const result = await add(40, 2); document.getElementById('result').innerHTML = `Result: ${result}`; } function updateFromPython(message) { document.getElementById('result').innerHTML = `Python says: ${message}`; } </script></head><body> <h1>Python-JavaScript Binding Demo</h1> <button onclick="callPython()">Call Python</button> <button onclick="callPythonWithArgs()">Call Python with Args</button> <div id="result"></div></body></html>"""webview.navigate(f"data:text/html,{quote(html)}") webview.run()Async Python Functions with JavaScript:
Webview Python supports binding asynchronous Python functions that can be called from JavaScript. This is useful for time-consuming operations that should not block the main thread.
Demo:
bind_in_local_async_by_asyncio_guest_win32_wip.py
,
importasynciofromwebview.webviewimportWebview, Size, SizeHintwebview=Webview(debug=True) # Async Python function that can be called from JavaScriptasyncdefdelayed_message(message, delay=1): # Simulating a time-consuming operationawaitasyncio.sleep(delay) returnf"Async response after {delay}s: {message}"# Async function with progress reportingasyncdefprocess_with_progress(steps=5, step_time=1): results= [] foriinrange(1, steps+1): awaitasyncio.sleep(step_time) # Report progress to JavaScriptprogress= (i/steps) *100webview.eval(f"updateProgress({progress}, 'Processing: Step {i}/{steps}')") results.append(f"Step {i} completed") return { "status": "complete", "steps": steps, "results": results } # Bind async Python functionswebview.bind("delayedMessage", delayed_message) webview.bind("processWithProgress", process_with_progress) # HTML/JavaScripthtml="""<html><head> <script> async function callAsyncPython() { try { document.getElementById('result').innerHTML = "Waiting for async response..."; const result = await delayedMessage("Hello from async world!", 2); document.getElementById('result').innerHTML = result; } catch (err) { document.getElementById('result').innerHTML = `Error: ${err}`; } } function updateProgress(percent, message) { document.getElementById('progress').style.width = percent + '%'; document.getElementById('progress-text').textContent = message; } </script></head><body> <button onclick="callAsyncPython()">Call Async Python</button> <div id="result"></div> <div id="progress" style="background-color: #ddd; width: 100%"> <div id="progress-bar" style="height: 20px; background-color: #4CAF50; width: 0%"></div> </div> <div id="progress-text"></div></body></html>"""webview.navigate(f"data:text/html,{quote(html)}") webview.run()For a more complete example, see
and
in the examples directory.
Features
Create desktop applications using HTML, CSS, and JavaScript
Load local HTML files or remote URLs
Bidirectional Python-JavaScript communication
Support for async Python functions with JavaScript promises
Progress reporting for long-running tasks
Window size and title customization
Debug mode for development
Cross-platform support (Windows, macOS, Linux)
Development
Setup Development Environment
# Install Python build tools pip install --upgrade pip build twine # Install GitHub CLI (choose one based on your OS):# macOS brew install gh # Windows winget install GitHub.cli # or choco install gh # Linux (Debian/Ubuntu) curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \ &&echo"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main"| sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \ && sudo apt update \ && sudo apt install ghRunning Tests
python -m unittest discover testsProject Structure
webview_python/ ├── src/ │ ├── webview.py # Main webview implementation │ └── ffi.py # Foreign Function Interface ├── examples/ # Example applications ├── tests/ # Unit tests └── README.md # Documentation Release Process
For maintainers who want to release a new version:
Test
# Install dependencies if not installed pip install -r requirements.txt # Run tests pytest # Build wheels python -m build -n -wUpdate Version
# Ensure you have the latest code git pull origin main # Update version in pyproject.toml# Edit version = "x.y.z" to new version number
Create Release
# Commit changes old_version=1.1.1 new_version=1.1.2 git add pyproject.toml README.md git commit -m "Bump version to ${new_version}" git push origin main # Create and push tag git tag v${new_version} git push origin v${new_version}# Create GitHub release gh release create v${new_version} --title "${new_version}" \ --notes "Full Changelog: https://github.com/congzhangzh/webview_python/compare/v${old_version}...v${new_version}"
Monitor Release
Check GitHub Actions progress in the Actions tab
Verify package on PyPI after workflow completion
First-time Release Setup
PyPI Setup
Create account:
https://pypi.org/account/register/
Generate API token:
https://pypi.org/manage/account/token/
GitHub Setup
Repository Settings → Secrets and variables → Actions
Add new secret: PYPI_API_TOKEN with PyPI token value
Roadmap
Publish to PyPI
Setup GitHub Actions for CI/CD
Add async function support
Add preact example
Add three.js example
Add three.js fiber example
Add screen saver 4 window example
Add MRI principle demo example by three.js fiber
Add screen saver 4 windows with MRI principle demo example by three.js fiber
TBD
CTRL-C support
References
License
This project is licensed under the MIT License - see the
file for details.