pythonpython-3.xibm-doors

Command works on Command Prompt but it does not work when called with subprocess.run() or os.system() in python


Python 3.10.6 Windows 10

I have a python function that executes a DXL script using subsystem.run() or os.system() (whichever works best I guess). The problem is that when I run a custom command using python it does not work, but when I paste the same command in the command prompt, it works. I should also clarify that command prompt is not the ms store windows terminal (cannot run ibm doors commands there for some reason). It is the OG prompt

I need to use both python and IBM Doors for the solution. Here is a summer version of my code (Obviously, the access values are not real):

    @staticmethod
    def run_dxl_importRTF():
        dquotes = chr(0x22) # ASCII --> "

        module_name = "TEST_TEMP"
        script_path = "importRTF.dxl"
        script_do_nothing_path = "doNothing.dxl"
        user = "user"
        password = "pass"
        database_config = "11111@11.11.1111.0"
        doors_path = dquotes + r"C:\Program Files\IBM\Rational\DOORS\9.7\bin\doors.exe" + dquotes
        file_name = "LIBC_String.rtf"
        
        # Based On: 
        # "C:\Program Files\IBM\Rational\DOORS\9.7\\bin\doors.exe" -dxl "string pModuleName = \"%~1\";string pFilename = \"%~2\";#include <importRTF.dxl>" -f "%TEMP%" -b "doNothing.dxl" -d 11111@11.11.1111.0 -user USER -password PASSWORD

        script_arguments = f"{dquotes}string pModuleName=\{dquotes}{module_name}\{dquotes};string pFileName=\{dquotes}{file_name}\{dquotes};#include <{script_path}>{dquotes}"
        command = [doors_path, "-dxl", script_arguments, "-f", "%TEMP%", "-b", script_do_nothing_path, '-d', database_config, '-user', user, '-password', password]
        
        res = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)

        print(f"COMMAND:\n{' '.join(res.args)}")
        print(f"STDERR: {repr(res.stderr)}")
        print(f'STDOUT: {res.stdout}')
        print(f'RETURN CODE: {res.returncode}')

        
        return

PYTHON SCRIPT OUTPUT:

    COMMAND:
    "C:\Program Files\IBM\Rational\DOORS\9.7\bin\doors.exe" -dxl "string pModuleName=\"TEST_TEMP\";string pFileName=\"LIBC_String.rtf\";#include <importRTF.dxl>" -f %TEMP% -b doNothing.dxl -d 11111@11.11.1111.0 -user USER_TEMP -password PASS_TEMP
    STDERR: 'The system cannot find the path specified.\n'
    STDOUT:
    RETURN CODE: 1

When I run the same command in the command prompt, it works (dxl script is compiled). I identified the problem which is the script_argument variable. Meaning that, when I try to just enter the IBM Doors server without compiling a DXL script, it works on python and the command prompt.

The python script needs to be dynamic meaning that all of the initial declared variables can change value and have a path string in it. I am also trying to avoid .bat files. They also did not work with dynamic path values

Thanks for your time

I tried:


Solution

  • When calling subprocess.run with a command list and shell=True, python will expand the command list to a string, adding more quoting along the way. The details are OS dependent (on Windows, you always have to expand the list to a command) but you can see the result via the subprocess.list2cmdline() function.

    Your problem is these extra escapes. Instead of using a list, build a shell command string that already contains the escaping you want. You can also use ' for quoting strings so that internal " needed for shell quoting can be entered literally.

    Putting it all together (and likely messing something up here), you would get

    @staticmethod
    def run_dxl_importRTF():
        module_name = "TEST_TEMP"
        script_path = "importRTF.dxl"
        script_do_nothing_path = "doNothing.dxl"
        user = "user"
        password = "pass"
        database_config = "11111@11.11.1111.0"
        doors_path = r"C:\Program Files\IBM\Rational\DOORS\9.7\bin\doors.exe"
        file_name = "LIBC_String.rtf"
        script_arguments = (rf'string pModuleName=\"{module_name}\";'
            'string pFileName=\"{file_name}\";'
            '#include <{script_path}>')
        command = (f'"{doors_path}" -dxl "{script_arguments}" -f "%TEMP%"'
            ' -b "{script_do_nothing_path}" -d {database_config}'
            ' -user {user} -password {pass}')
        
        res = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
    
        print(f"COMMAND:\n{' '.join(res.args)}")
        print(f"STDERR: {repr(res.stderr)}")
        print(f'STDOUT: {res.stdout}')
        print(f'RETURN CODE: {res.returncode}')