Python bindings for the webview library, allowing you to create desktop applications with web technologies.
pip install webview_python
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
orC:\path\to\libs
- Can be a web URL:
Example usage:
# Using an internal HTTP server
export WEBVIEW_DOWNLOAD_BASE="http://internal-server.com/webview-libs"
# Using a network share on Windows
set WEBVIEW_DOWNLOAD_BASE=\\\\server\\share\\webview-libs
# Using a mounted path on Linux
export 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/...
from webview.webview import Webview
from urllib.parse import quote
html = """
<html>
<body>
<h1>Hello from Python Webview!</h1>
</body>
</html>
"""
webview = Webview()
webview.navigate(f"data:text/html,{quote(html)}")
webview.run()
from webview.webview import Webview
import os
webview = 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()
from webview.webview import Webview
webview = Webview()
webview.navigate("https://www.python.org")
webview.run()
from webview.webview import Webview, Size, SizeHint
from urllib.parse import quote
webview = Webview(debug=True)
# Python functions that can be called from JavaScript
def hello():
webview.eval("updateFromPython('Hello from Python!')")
return "Hello from Python!"
def add(a, b):
return a + b
# Bind Python functions
webview.bind("hello", hello)
webview.bind("add", add)
# Configure window
webview.title = "Python-JavaScript Binding Demo"
webview.size = Size(640, 480, SizeHint.FIXED)
# Load HTML with JavaScript
html = """
<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()
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, bind_in_local_async.html
import asyncio
from webview.webview import Webview, Size, SizeHint
webview = Webview(debug=True)
# Async Python function that can be called from JavaScript
async def delayed_message(message, delay=1):
# Simulating a time-consuming operation
await asyncio.sleep(delay)
return f"Async response after {delay}s: {message}"
# Async function with progress reporting
async def process_with_progress(steps=5, step_time=1):
results = []
for i in range(1, steps + 1):
await asyncio.sleep(step_time)
# Report progress to JavaScript
progress = (i / steps) * 100
webview.eval(f"updateProgress({progress}, 'Processing: Step {i}/{steps}')")
results.append(f"Step {i} completed")
return {
"status": "complete",
"steps": steps,
"results": results
}
# Bind async Python functions
webview.bind("delayedMessage", delayed_message)
webview.bind("processWithProgress", process_with_progress)
# HTML/JavaScript
html = """
<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 bind_in_local_async.py and bind_in_local_async.html in the examples directory.
- 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)
# 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 gh
python -m unittest discover tests
webview_python/
├── src/
│ ├── webview.py # Main webview implementation
│ └── ffi.py # Foreign Function Interface
├── examples/ # Example applications
├── tests/ # Unit tests
└── README.md # Documentation
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 -w
-
Update 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
-
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
- 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
- CTRL-C support
This project is licensed under the MIT License - see the LICENSE file for details.