Search code examples
pythonshellescapingscons

How to escape an environment variable in a SCons action?


I have a build command that runs a Python script. Because the python command is sometimes python and sometimes python3 (depending on operating system), I instead use the full path which I'm keeping in an environment variable.

However, this path sometimes has weird characters like spaces, which need to be escaped. For example .../Program Files/... in Windows.

SCons doesn't seem to automatically escape a variable when it substitutes it in the command. When I run this script:

import sys
env = Environment()
env.Replace(PYTHON_EXECUTABLE=sys.executable)
foo = env.Alias('foo', [], '$PYTHON_EXECUTABLE my-script.py')
env.AlwaysBuild(foo)

I get:

scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
C:\Program Files\Python311\python.exe my-script.py
'C:\Program' is not recognized as an internal or external command,
operable program or batch file.
scons: *** [foo] Error 1
scons: building terminated because of errors.

I don't want to put the path in double quotes because they still allow some characters to be expanded on Linux. On the other hand, Windows doesn't support single quotes.

Is there any simple portable method to escape a part of a command, regardless of what characters are there?


Solution

  • SCons provides an escape function that seems to do exactly what you need.

    It is predefined in an environment variable ESCAPE and it can be called in the action string like this: ${ESCAPE(YOUR_VARIABLE)}.

    Fixed version of your script

    import sys
    env = Environment()
    env.Replace(PYTHON_EXECUTABLE=sys.executable)
    foo = env.Alias('foo', [], '${ESCAPE(PYTHON_EXECUTABLE)} my-script.py')
    env.AlwaysBuild(foo)