Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow shebang with %ENVIRONMENT VARIABLES% in it #209

Open
sdementen opened this issue Feb 9, 2022 · 0 comments
Open

Allow shebang with %ENVIRONMENT VARIABLES% in it #209

sdementen opened this issue Feb 9, 2022 · 0 comments

Comments

@sdementen
Copy link

sdementen commented Feb 9, 2022

I am using the shebang to specify the specific version of the intepreter to be used (3.8, 3.9, ...) knowing that the user's laptop that will run the pyz have the different versions installed as "%USERPROFILE%\AppData\Local\Programs\Python\PythonNN".
Hence I would need the shebang line to accept the environment variable USERPROFILE.

The current shebang line does not allow this and shiv will "expand_user" the python interpreter (for '~').

The workaround I found (on windows) is to use a shebang line looking like
cmd.exe /C call "%USERPROFILE%\AppData\Local\Programs\Python\Python38\python.exe"

However, specifying such an argument via the CLI is cumbersome:

  1. one need to remember this specific shebang construct
  2. the %USERPROFILE% will be interpreted directly by the shell and so will come to python already replaced.

What would be nice is to be able to specify a python interpreter like "$USERPROFILE$\AppData\Local\Programs\Python\Python38\python.exe" and have shiv detect the "$" and replace the intepreter by the ad-hoc shebang line with the $ replaced by %.

In the general case, when the interpreter path includes the %USERPROFILE% string, it could even be nice to automatically replace it by the shebang with the dynamic $USERPROFILE$ (this could be disabled through an option).

The two logics are implemented and illustrated here below:

import os
from pathlib import Path


def replace_userprofile(python):
    r"""convert a path string with "C:\Users\name-of-user\AppData\Local\Programs\Python\Python38\python.exe" to
    the path string $USERPROFILE$\AppData\Local\Programs\Python\Python38\python.exe
    """
    if (user_profile := os.environ.get("USERPROFILE")) :
        try:
            return str("$USERPROFILE$" / Path(python).relative_to(Path(user_profile)))
        except ValueError:
            return python


def build_shebang(python):
    # handle $ENVIRONMENT_VARIABLES$ in python path (use an trampoline shebang)
    if "$" in python:
        # if the python path contains a $, we replace it by % and use a cmd.exe shebang to trampoline to python
        return f'cmd.exe /C call "{python.replace("$", "%")}"'
    else:
        return python


if __name__ == "__main__":
    for python in [
        r"C:\Users\GFJ138\AppData\Local\Programs\Python\Python38\python.exe",
        r"$USERPROFILE$\AppData\Local\Programs\Python\Python38\python.exe",
        r"C:\Program Files\Python\Python38\python.exe",
    ]:
        print(
            f"Original interpreter: {python}\n"
            f"Dynamic interpreter:  {replace_userprofile(python)}\n"
            f"Shebang:              {build_shebang(replace_userprofile(python))}\n"
        )

which outputs (given USERPROFILE=C:\Users\JohnDoe):

Original interpreter: C:\Users\JohnDoe\AppData\Local\Programs\Python\Python38\python.exe
Dynamic interpreter:  $USERPROFILE$\AppData\Local\Programs\Python\Python38\python.exe
Shebang:              cmd.exe /C call "%USERPROFILE%\AppData\Local\Programs\Python\Python38\python.exe"

Original interpreter: $USERPROFILE$\AppData\Local\Programs\Python\Python38\python.exe
Dynamic interpreter:  $USERPROFILE$\AppData\Local\Programs\Python\Python38\python.exe
Shebang:              cmd.exe /C call "%USERPROFILE%\AppData\Local\Programs\Python\Python38\python.exe"

Original interpreter: C:\Program Files\Python\Python38\python.exe
Dynamic interpreter:  C:\Program Files\Python\Python38\python.exe
Shebang:              C:\Program Files\Python\Python38\python.exe
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant