niess / python-appimage

AppImage distributions of Python
https://python-appimage.readthedocs.io/en/latest/
GNU General Public License v3.0
170 stars 24 forks source link

backup original sys.executable path #76

Closed manfred-kaiser closed 3 months ago

manfred-kaiser commented 3 months ago

When you change the sys.executable path to the AppImage, other modules cannot start the internal interpreter because it launches the AppImage again instead of the included Python binary.

By adding the mentioned changes to the init_appimage module, it will be possible to access the original/unpatched sys.executable value.

This pull request stores the original sys.executable as executable_original, which allows addressing the included Python binary instead of the AppImage. Although this is not a Python default, it enables module authors to create custom entry point scripts that need to execute the Python binary.

Note: I'm working on an AppImage entry point script to enhance Python AppImage applications: https://github.com/ssh-mitm/appimage

This entry point script makes it possible to start the application by defining an environment variable in the AppRun script, but other methods can also be supported:

export PYTHON_ENTRY_POINT="ssh-mitm"
"$APPDIR/opt/python3.11/bin/python3.11" -m appimage "$@"

The appimage module allows interaction with the AppImage using additional arguments:

options:
  --python-help         Show this help message and exit.
  --python-interpreter  Start the Python interpreter.
  --python-venv PYTHON_VENV_DIR
                        Create a virtual environment pointing to the AppImage.
  --python-entry-point PYTHON_ENTRY_POINT
                        Start a Python entry point from console scripts (e.g., ssh-mitm).

Additional Note: The appimage module only provides an entry point, which can be used inside an AppImage to help initialize Python applications. It can be used in different AppImage setups like yours (python-appimage), appimage-builder, or custom setups.

Moreover, the appimage module aims to develop a unified interface, independent of the tool used to create the AppImage. This will allow different implementations to work together seamlessly, making Python AppImages more compatible and easier to use.

manfred-kaiser commented 3 months ago

I found an official method to get the path to the included python appimage.

sys.base_prefix can be used to find the directory where the python files are stored in the AppImage.

>>> import os, sys
>>> os.path.join(                  
...    sys.base_prefix,            
...    "bin",                      
...    f"python{sys.version_info[0]}.{sys.version_info[1]}"
... )
'/tmp/.mount_pythonZL5S7b/opt/python3.9/bin/python3.9'

So there is not need to add additional (unofficial) properties to the sys module.

niess commented 3 months ago

Hello @manfred-kaiser ,

thank you for raising this point. I did not realize that setting the sys.executable path could have such side effects. The initial intent was to mimic the Python AppImage being a Python runtime. But, as you might have seen, this is somehow a hack. Though, I cannot exactly remember why, but it also serves some purpose in distinguishing a native Python runtime from an AppImage one.

Anyway, hopefully you could find a workaround.

This appimage package looks great. I understand that user could include it in their application, providing extra functionalities (the like --appimage-* commands).

manfred-kaiser commented 3 months ago

This appimage package looks great. I understand that user could include it in their application, providing extra functionalities (the like --appimage-* commands).

The idea behind this package comes from shiv. With shiv it's possible to create PEP-441 compatible python zip applications.

I used shiv a lot to deploy my applications in production environments, because they are self contained and all dependencies are included in the package. It's like "copy&paste" 😉

With shiv, it's also possible to define different entry-points when starting the application. This is done with environment variables like SHIV_ENTRY_POINT .

For example, if you want to deploy a django app, you have at least 2 entry points. One for the wsgi server (e.g. gunicorn) and the django admin command (django-admin). All you have to do is to define a different entry point for gunicorn in a systemd service file and provide a shell script to setup to environment variables for the django-admin command.

But shiv has some drawbacks compared to other deployments. One of the biggest drawbacks is that the shiv application unpacks the whole application in a temporary dictionary. The default is the home directory, but system users often does not have a writeable home directory. Another drawback is the startup time. The first startup takes very long because of the unpacking and all subsequent startups checks if the application is already unpacked. So starting a django app can take several secons and the starttime of really big applications can take up to 1 minute.

I already used AppImages for my SSH-MITM project which works really well, but was not able to migrate my django project to AppImage because of the mentioned problems.

This was the reason, why I wrote the appimage module.

The appimage module might not be necessary for most applications, because in most cases it's sufficient to start a single command.

But in rare cases like self contained django applications this might be a huge step forward to streamline the deployment.

I have released appimage 1.0.0 which is stable enough to be used in production environments 😃

In the future I want to add a better compatibility with shiv by adding more environment variables and command line arguments which should allow developers to switch from shiv to AppImages by only replacing the shiv file with an AppImage.