10

I am new to child_process and I want to experiment with its capabilities.

Is there any way to pass a function and arguments to a python file, using spawn (or exec or execFile is spawn cannot do it)?

I want to do something like (pseudocode)

spawnORexecORexefile (python path/to/python/file function [argument1, argument2] ) 

or maybe

spawnORexecORexefile (python path/to/python/file function(argument1, argument2) ) 

Please explain and maybe give an example, because I am a newbie

How I am doing it now?

in node

 var process = spawn('python', [path/to/pythonFile.py, 50, 60] );  

in pythonFile.py

import sys 
import awesomeFile

hoodie = int(sys.argv[1])
shoe = int(sys.argv[2])

awesomeFile.doYourMagic().anotherThing(hoodie, shoe)

as you can see, from node, I send data to pythonFile and then to awesomeFile, to a specific function

I would like to "cut the middle man" and remove the pythonFile and send data from node directly to the awesomeFile file, to a specific function. This is why I am asking

Thanks

codebot
  • 517
  • 8
  • 29
  • 55

2 Answers2

4

You can run a specific Python function from the command-line using the form python -c 'import foo; print foo.hello()' (from https://stackoverflow.com/a/3987113/5666087).

Place both the files below in the same directory, and run with node index.js. You should see the following output:

Hoodie: 10
Shoe: 15

awesomeFile.py

def myfunc(hoodie, shoe):
    hoodie = int(hoodie)
    shoe = int(shoe)
    print("Hoodie:", hoodie)
    print("Shoe:", shoe)

index.js

const { spawn } = require('child_process');
let hoodie = 10,
    shoe = 15;
const result = spawn("python",
    ["-c", `import awesomeFile; awesomeFile.myfunc(${hoodie}, ${shoe})`])
result.stdout.pipe(process.stdout)
jkr
  • 17,119
  • 2
  • 42
  • 68
  • Bad news. I tested it and no matter how I syntax the `spawn` part in node, I get an error, spawn exits with code 1, ` Uncaught Fatal Exception - There was an uncaught exception, and it was not handled by a domain or an uncaughtException event handler. ` . What am I missing here ? – codebot Jul 29 '20 at 13:35
  • If I open a cmd and cd to a folder that contains a python file and try to do `python -c 'import test ; test.myFunc()'` I get ` File "", line 1 'import ^ SyntaxError: EOL while scanning string literal` – codebot Jul 29 '20 at 14:23
  • maybe its a syntax thing. The way you construct spawn maybe fits the `exec` better than the `spawn`, because your syntax its closer to shell syntax. Maybe `spawn` needs another syntax or other code entirely – codebot Jul 29 '20 at 14:58
  • Are you on windows? Can you try with double quotes? `python -c "import test ; test.myFunc()"`. – jkr Jul 29 '20 at 15:47
  • yes I am on windows. Wait, this isnt global for different OS? Anyway, I tried that and during the `result.on('exit'` I get exit code 2 `Unused (reserved by Bash for builtin misuse)` – codebot Jul 29 '20 at 16:00
  • Oh and btw this works for me in a Windows cmd `python -c "import testPY; testPY.myfunc()"`, really close to your last suggestion. Works in cmd, not in node spawn. I am kinda lost right now, sorry – codebot Jul 29 '20 at 16:04
0

You can group all the relevant functions you want to call to class and make a dictionary out of a class that maps to the class function. You can directly call awesome.py without an intermediate index.py. You can extend the class AwesomeFile with your methods

The follow program will take user input -

  1. which python file to run
  2. which method to run
  3. method arguments
  4. Number of arguments mismatch
  5. What if unknown methods are given

awesomeFile.py

import sys

class AwesomeFile:

    def __init__(self):
        pass

    def doYourMagic(self):
        return self
    
    def anotherThing(self, hoodie, shoe):
        print(int(hoodie))
        print(int(shoe))

awesomeFile = AwesomeFile()
methods = {m:getattr(awesomeFile, m) for m in dir(AwesomeFile) if not m.startswith('__')}

def run():
    method_name = sys.argv[1]
    if method_name not in methods:
        print(f"Unknown Method {method_name}")
        return
    methodArgCount = methods[method_name].__code__.co_argcount
    if methodArgCount - 1 != len(sys.argv[2:]):
        print(f"Method {method_name} takes {methodArgCount - 1} arguments but you have given {len(sys.argv[2:])}")
        return
    
    methods[method_name](*sys.argv[2:])

if __name__ == "__main__":
    run()

index.js

Note** - You would to install prompt - npm i prompt

'use strict';
var prompt = require('prompt');
const { spawn } = require( 'child_process' );

var prompt_attributes = [
    {        
        name: 'pythonFilePath'
    },
    {   
        name: 'cmdLineArgs'
    }
];

prompt.start();

prompt.get(prompt_attributes, function (err, result) {
    if (err) {
        console.log(err);
        return 1;
    }else {
        console.log('Command-line received data:');
        var filePath = result.pythonFilePath;
        var cmdLineArgs = result.cmdLineArgs;
        var args = cmdLineArgs.split(" ");
        args.unshift(filePath);
        
        const pythonProgram = spawn( 'python' , args);

        pythonProgram.stdout.on( 'data', data => {
            console.log( `stdout:\n\n ${data}` );
        } );

        pythonProgram.stderr.on( 'data', data => {
            console.log( `stderr: ${data.data}` );
        } );

        pythonProgram.on( 'close', code => {
            console.log( `child process exited with code ${code}` );
        } );
    
    }
});

To run the program -

I/O:

Argument Mistmatch -

prompt: Python File Path. Give absolute or relative path: ../python_files/awesomeFile.py # python file can be any location in the system
prompt: Command Line Arguments. Format = func_name arguments_list (Ex addFunc 1 2):  anotherThing 1
Command-line received data:
stdout:

 Method anotherThing takes 2 arguments but you have given 1

child process exited with code 0

Function Not found

prompt: Python File Path. Give absolute or relative path:  ../python_files/awesomeFile.py
prompt: Command Line Arguments. Format = func_name arguments_list (Ex addFunc 1 2):  helloworld 1 2
Command-line received data:
stdout:

 Unknown Method helloworld

child process exited with code 0

Success Case:

prompt: Python File Path. Give absolute or relative path:  ../python_files/awesomeFile.py
prompt: Command Line Arguments. Format = func_name arguments_list (Ex addFunc 1 2):  anotherThing 50 60
Command-line received data:
stdout:

 50
60

child process exited with code 0
bigbounty
  • 16,526
  • 5
  • 37
  • 65