Search code examples
pythoncmdsubprocessnameerror

NameError when executing python script using subprocess module but code executing from IDLE


I was recently using the subprocess module and it's run method to execute os commands through python only and get the output, since I was trying to make a custom command prompt in tkinter.

The way that command prompt handles commands I write into it is as follows -:

  1. So when I write a command as input I split it from spaces for e.g.

    INPUT: cmd exec python test.py

    OUTPUT: ['cmd', 'exec', 'python', 'test.py'] # i.e. [cmd, arg1, arg2, ...]

  2. Now I convert the above list into a dictionary with two keys -:

    • The first key is 'name' which has the value as the name of the command.
    • The second key is 'args' which is a concatenated string value (of all the other list items except the first list item from the first step).

    So it becomes -:

    command_input = {'name' : 'python', 'args' = 'test.py'} # i.e. {'name': cmd, 'args': concat_str_of_args}
    
  3. Now the dictionary made in the second process, is passed into a module, which interprets the command and it converts it into a normal command prompt command(NOTE: Previously the command was a custom one based on my own custom made syntax cmd exec command_prompt_command) in string form and returns it as a dict called command_output, with it's args as the list from step 1 ([cmd, arg1, arg2.....]).

    Like so -:

    command_output = my_module.convert_to_cmd_form(command_input) # returns a dictionary like so -: {'args' : ['python', 'test.py']}
    

Now I try executing a python script I made to test if this was working, The code for the test file is -:

# CODE FOR TEST FILE
print('This is a special test for the terminal cmd integration!')

And executing this file by IDLE I get the desired output with no error:

This is a special test for the interstellar terminal cmd integration!

While when I do the same with my custom command prompt which in the backend uses a special subprocess python script to run this test.py it gives a name error:

Output of test.py using my script

And I am not able to properly understand the reason for the same the code for executing scripts is somewhat like so:

os.environ["PYTHONUNBUFFERED"] = "1"
print([command_output['args'][0]], ' '.join(command_output['args'][1 : ]), ' '.join(command_output['args'][1 : ]).encode('utf-8'))
result = subprocess.run([command_output['args'][0]], input = ' '.join(command_output['args'][1 : ]).encode('utf-8'), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell = True, env = os.environ, cwd = 'C:')

The print statement here was for debugging to check if all values were being parsed as expected.

['python'] test.py b'test.py'

Solution

  • my special subprocess python script to run this test.py it gives a name error:

    Your mre from chat discussion:

    import subprocess
    
    command_output = {'args':['python',r'test.py'] }
    result = subprocess.run([command_output['args'][0]],
                            input = ' '.join(command_output['args'][1 : ]).encode('utf-8'),
                            stdout=subprocess.PIPE,
                            stderr=subprocess.STDOUT,
                            shell = True, env = os.environ, cwd = 'C:')
    

    Include the full path to the file to alleviate the NameError: name \'test\' is not defined\r\n' Exception.

    command_output = {'args':['python',r'c:\full\path\test.py'] }
    

    For the following solutions you would need to parse command_output appropriately.

    This form works

    args = ['python', '-m', 'test']
    other = subprocess.run([args,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.STDOUT,
                            shell = True, env = os.environ, cwd = 'C:')
    

    Using the input keyword argument, you need to send the python commands you would use if you were typing/executing from a python shell.

    args = [b'python']
    cmd = b'import test'
    another = subprocess.run(args,
                             input = cmd,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.STDOUT,
                             shell = True, env = os.environ, cwd = 'C:')
    

    This one courtesy of this answer https://stackoverflow.com/a/1027739/2823755. Again you may need to include the full path to the file.

    args = [b'python']
    cmd = b'''exec(open("test.py").read())'''
    another1 = subprocess.run(args,
                             input = cmd,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.STDOUT,
                             shell = True, env = os.environ, cwd = 'C:')