astral-sh / astral-sh/python-build-standalone
Create an application bundle if UV installs its Python on a Mac
- Dominant language
- Python
- Stars
- 4.4k
- Forks
- 314
- Avg merge
- 1d 9h
- Merged PRs (30d)
- 27
Description
On the Mac, some features require to be activated in the 'System Settings'. Some of them (e.g. location services) are available to a Python script, if that the *script* is bundled. Others, such as notifications, seem to need a bundled *Python executable*. While it is not obvious to me, where these differences arise, I found a (comparably) simple solution for the Python installed via `uv`.
I bundled the executable that I installed via `uv python install 3.13` (or any other version I guess). Then, I moved the 4 directories from `share/uv/python/cpython.../` into the `Contents` folder of the created application bundle. That way, Mac OS will show the Python executable in the, e.g., 'Notifications' settings the first time I try to send one. and, subsequently, ask if I would allow it for Python.
Please note that I tried an 'unbundled ~~framework~~ system python' (Sequoia, would not work) and a 'bundled script' (would not work either). I could only make notifications work via a 'bundled Python'. Since these admittedly superficial tests indicate that it might only require two more subdirectories and a tiny `info.plist` xml file, it would be great if this could be considered. As a side effect, the requirement to bundle a script to work with 'location services' would also be removed, at least as long as I am willing to give every Python script this permission. I would imagine that similar things exist beside the mentioned two, which would also benefit from this 'bundling'.
I made two Python bundles (3.12, 3.13), just to see if several versions are possible and, yes, both show up under their respective names (I gave them) in the 'System Settings'.
To validate this, please find the minimal Python script:
```python
import sys
from PyQt6.QtWidgets import QApplication, QSystemTrayIcon, QMainWindow
from PyQt6.QtGui import QIcon, QPixmap
from PyQt6.QtCore import Qt
if __name__ == "__main__":
app = QApplication(sys.argv)
ex = QMainWindow()
ex.setWindowTitle("Notification test")
ex.show()
tray = QSystemTrayIcon()
pixmap = QPixmap(32, 32)
pixmap.fill(Qt.GlobalColor.transparent)
icon = QIcon(pixmap)
tray.setIcon(icon)
tray.show()
title = "Important!"
msg = "This is a cross-platform desktop notification."
tray.messageClicked.connect(lambda: print("Notification clicked!"))
tray.showMessage(title, msg, QSystemTrayIcon.MessageIcon.Warning)
sys.exit(app.exec())
```
and some screenshots. I used the logo for a better mockup how it could look like.
Contributor guide
Assessment
This issue has not been assessed yet.