Enhances the user experience of Python scripts run via double-click on Windows
Project description
What is pydblclick ?
(formerly known as pyexewrap — renamed before the first PyPI release, since the old
name referenced the deprecated py.exe launcher and suggested exe-building tools)
pydblclick makes Python scripts pleasant to run by double-click on Windows — for you, your colleagues, or anyone you share a one-file script with:
- The console window never flashes away: a pause prompt appears at the end of the script, including when an exception occurs (even a syntax error), so the traceback is always readable.
- Scripts that declare their dependencies inline (PEP 723)
are executed through uv: dependencies are resolved
automatically in an ephemeral environment — the recipient never manages venvs or
pip install. - An interactive menu at the pause prompt:
<i>opens a Python console with the script's real variables (post-mortem debugging),<c>opens a cmd console,<r>restarts the script. .pyw(windowed) scripts run with no console at all (they are registered withpythonw.exe) — but if they crash, a console is created on the spot showing the script's output and the traceback, instead of dying silently.- When a script is run from a console, called by another script or a batch file, pydblclick stays out of the way: no pause, exit codes and arguments faithfully propagated.
Python's native problems for Windows users
- A double-clicked
.pyfile pops a console that flashes away, unless the last line is a blockinginput()— and even then, any exception (a syntax error, a missing module) skips that line and the window vanishes before the traceback can be read. - That blocking
input()becomes undesirable when the same script is run from a console or called by another script. - A
.pywscript that crashes dies silently: there is no console to show the traceback. - Sharing a script that needs
requestsorpandasmeans asking the recipient to understand pip, venvs, and PATH — or it just crashes withModuleNotFoundError.
Installation
pip install <path-to-this-repo> (PyPI package coming soon)
pydblclick register
pydblclick register sets pydblclick as the default handler for .py/.pyw double-clicks
using the standard Windows mechanism (ProgID + UserChoice). This works on all Python
installations — classic installer and MSIX Python Manager (see
MSIX_COMPATIBILITY.md). A backup of the previous file
associations is saved automatically before any change.
To undo everything:
pydblclick unregister
To inspect the Windows file association chain (and detect MSIX interference):
pydblclick diagnose
For automatic dependency resolution (PEP 723 scripts), also install uv. Without uv, PEP 723 scripts still run with plain Python, and a message explains what to install.
Usage
Double-click (the main purpose)
Once registered, every .py/.pyw file you double-click runs enhanced. Nothing to
add to the scripts themselves. Try the scripts in the examples folder.
Sharing dependency-aware one-file scripts (PEP 723 + uv)
Declare dependencies at the top of the script, in standard PEP 723 format:
# /// script
# requires-python = ">=3.11"
# dependencies = ["requests", "rich"]
# ///
import requests
...
On a machine with pydblclick + uv, double-clicking this file "just works": uv resolves
the dependencies in an ephemeral environment, and pydblclick keeps the window open with
its usual menu. This is a standard format — the same file also runs with uv run alone
on any platform. Use uv add --script myscript.py requests to maintain the block.
Opting a script out
Add this comment anywhere in a script to make pydblclick step aside (plain Python behavior, no pause):
# pydblclick: off
Pause only on error
To make an individual script skip the final pause unless an exception occurred:
pydblclick_customizations['must_pause_in_console'] = False
Command line
pydblclick <script.py> [args...] (or python -m pydblclick <script.py> [args...]) wraps
a script explicitly. In a console there is no pause; set the
pydblclick_simulate_doubleclick env var to force double-click behavior (useful in
batch files and tests).
Custom icons
Scripts launched via pydblclick show the registered Python icon. For a custom icon, create a shortcut to the script (ALT+drag & drop) and set the icon in its properties.
How it works
Two processes (see CLAUDE.md architecture notes and ROADMAP.md):
- a thin parent supervisor (
python -m pydblclick) which guarantees the window survives anything — evenos._exit(), a native crash, or a script that closes stdin; - a child engine (
python -m pydblclick._child) which runs your script with exact plain-Python semantics (runpy), shows clean tracebacks (no wrapper frames), and owns the pause menu. For PEP 723 scripts the child runs inside the uv-provisioned environment.
No monkey-patching, no code injection: __name__, __file__, sys.argv, exit codes
and exit()/quit() behave exactly as with plain Python.
Legacy: the shebang method (deprecated)
Before the 2026 pivot (under the project's former name pyexewrap), scripts were enhanced
individually with a shebang line (#!/usr/bin/env python -m pydblclick) read by the classic
py.exe launcher, and installation went through a system-wide PYTHONPATH (the helper scripts
have since been removed). This mechanism still works on classic-installer systems
provided pydblclick is importable by the system Python (pip install does that), but it is
a dead end:
- the classic
py.exelauncher is deprecated since Python 3.14 and will not be produced for Python 3.16+; - the MSIX Python Manager (Microsoft Store / "Python Install Manager" on python.org)
never reads shebangs on double-click, and its shebang support
does not allow arguments such as
-m pydblclick.
Use pydblclick register instead; per-script granularity is provided by the
# pydblclick: off directive. See MSIX_COMPATIBILITY.md for the
full compatibility matrix and history.
Compatibility with the MSIX Python Manager (python/pymanager)
The PythonSoftwareFoundation.PythonManager MSIX package intercepts .py/.pyw
double-clicks through Windows App Model activation, bypassing shebangs and registry
ftype settings. pydblclick register works with it: the MSIX launcher honors
UserChoice pointing to the pydblclick.PyFile ProgID (confirmed by testing).
If double-clicks don't reach pydblclick, run pydblclick diagnose — it detects MSIX
interference and tells you what to fix. Details in
MSIX_COMPATIBILITY.md.
Note about py.exe
py.exe was the Windows wrapper for multiple Python interpreters, making pydblclick a
wrapper of a wrapper. Its pymanager successor confirms that launcher-level wrapping is
not extensible — which is why pydblclick now registers itself as the file handler, the
one mechanism every launcher must respect.
Todos
- Publish to PyPI (
pip install pydblclick) - Standalone
pydblclick.exehandler (no Python required to bootstrap; uv can even provision Python itself) - Offer to install uv when a PEP 723 script is double-clicked and uv is missing
- Context menu items "Run with pydblclick" / "Bypass pydblclick"
Contributions
Your contributions would be greatly appreciated. Feel free to copy the project.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pydblclick-0.2.0.tar.gz.
File metadata
- Download URL: pydblclick-0.2.0.tar.gz
- Upload date:
- Size: 35.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7504858c01b5b55a7f3dd4fed47653b9d738347b354d5942bbcb883957a0c21c
|
|
| MD5 |
e33a73b43ebb63ffc88dc77d86d2dedb
|
|
| BLAKE2b-256 |
7e35a9f41fbf70d0b471bdb3aa16b9e2b4328842e3988f1162ba937062c383fc
|
Provenance
The following attestation bundles were made for pydblclick-0.2.0.tar.gz:
Publisher:
publish.yml on TsKyrk/pydblclick
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pydblclick-0.2.0.tar.gz -
Subject digest:
7504858c01b5b55a7f3dd4fed47653b9d738347b354d5942bbcb883957a0c21c - Sigstore transparency entry: 2079930939
- Sigstore integration time:
-
Permalink:
TsKyrk/pydblclick@8903c9afd8017a37cd7c61fb11b41826458c1b30 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/TsKyrk
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8903c9afd8017a37cd7c61fb11b41826458c1b30 -
Trigger Event:
push
-
Statement type:
File details
Details for the file pydblclick-0.2.0-py3-none-any.whl.
File metadata
- Download URL: pydblclick-0.2.0-py3-none-any.whl
- Upload date:
- Size: 31.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2372f136b545c72353867bc1be45be85d9341dbaeb410e8b481c85b1b9da2282
|
|
| MD5 |
700828e8c227575319e064339ee01ae7
|
|
| BLAKE2b-256 |
00c85a2432dfc6fe44f8e0fbaef7d3b53179e9335444ce58d980d3770e17a641
|
Provenance
The following attestation bundles were made for pydblclick-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on TsKyrk/pydblclick
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pydblclick-0.2.0-py3-none-any.whl -
Subject digest:
2372f136b545c72353867bc1be45be85d9341dbaeb410e8b481c85b1b9da2282 - Sigstore transparency entry: 2079931160
- Sigstore integration time:
-
Permalink:
TsKyrk/pydblclick@8903c9afd8017a37cd7c61fb11b41826458c1b30 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/TsKyrk
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8903c9afd8017a37cd7c61fb11b41826458c1b30 -
Trigger Event:
push
-
Statement type: