Search code examples
pythonnode.jschild-processsys

Sys.argv not returning expected value in node with child_process data send to python script within node app


I have a nodejs app, and am using child_process to send data to be run in a python script. However, "sys.argv" only returns "script1.py", the file name, rather than the object I want to send to python.

Here is my nodejs:

app.get("/", (request, response) => {
    console.log('hi')
  var dataToSend;
  var nodeData = "jeff";
  console.log('breh')
  var obj = {obj1: image3v, obj2: image4v}
  const python = spawn('python', ['script1.py'], obj);
  console.log('welp')
  python.stdout.on('data', function (data) {
    dataToSend = data.toString();
  });
  
  python.stderr.on('data', data => {
    console.error(`stderr: ${data}`);
    console.log(data)
  })
  
  python.on('exit', (code) => {
    console.log('exited')
    console.log(dataToSend);
    //run new stuffhere
  });
})

My script1.py:

import sys

print('python begins')
print(sys.argv[0])
print(sys.argv[0][1])
print(sys.argv[0][2])
print(sys.argv)
print(sys.orig_argv)

However, all of these print statements in python print either 'script1.py', ['script1.py'], or one of the letters in script1.py via the [0][1], etc. If I try to do sys.argv[1], I get index out of bounds.

Looking at other references, my code should be working, but I think there's something I'm not seeing. I don't know what else to try to access the object.

Thanks.


Solution

  • To spawn an external command and pass arguments on the commandline, the arguments need to be serialized, for example, to a string. There are limits to the size of commandline arguments, so if they are too large, some other method must be used (e.g., passing via stdin/stdout, named pipes, etc.).

    Here's a demonstration of passing arguments from node to python.

    spawnSO.js:

    const { spawn } = require('node:child_process');
    
    const params = {"fred": 1, "wilma": "wife", "dino": ["barks", 2.718]};
    
    const python = spawn('python', ['spawned.py', JSON.stringify(params)]);
    
    python.stdout.on('data', (data) => {
      console.log(`stdout: ${data}`);
    });
    
    python.stderr.on('data', (data) => {
      console.error(`stderr: ${data}`);
    });
    
    python.on('close', (code) => {
      console.log(`child process exited with code ${code}`);
    });
    

    spawned.py:

    import sys
    
    print(sys.orig_argv)
    print("len(sys.argv): ", len(sys.argv))
    
    for k, arg in enumerate(sys.argv):
      print(f"argv num: {k}, argv: {arg}")
    
    import json
    
    from_json_string = json.loads(sys.argv[1])
    print(f"type of converted JSON: {type(from_json_string)}, loaded value: {from_json_string}")
    

    Here's the output:

    $ node spawnSO.js
    stdout: ['python', 'spawned.py', '{"fred":1,"wilma":"wife","dino":["barks",2.718]}']
    len(sys.argv):  2
    argv num: 0, argv: spawned.py
    argv num: 1, argv: {"fred":1,"wilma":"wife","dino":["barks",2.718]}
    type of converted JSON: <class 'dict'>, loaded value: {'fred': 1, 'wilma': 'wife', 'dino': ['barks', 2.718]}
    
    child process exited with code 0