Getting Exit Code (1) Error and Output in Error output using Process in Symfony

I’m developing an application using Symfony 3.4 and I have to use some python scripts. I used Symfony’s Process Component to execute my python script and I got an Exit Code: 1 (General Error) that I don’t understand. Moreover, I saw that my expected output appears in the ErrorOutput, is that normal?

Here is my python script (index.py) :

import scipy.stats as stats
import sys

#Kendall Coefficient

def kendallcoeff(x1,x2):
    tau, p_value = stats.kendalltau(x1,x2)
    return tau

sys.exit(float(kendallcoeff(sys.argv[1],sys.argv[2])))
#sys.exit(sys.argv)

And in my php class, I have this code :

$process = new Process("python3 python/index.py",null,["arg1" => $timeArray,"arg2" => $speedArray]);
$process->run();

When I uncomment sys.exit(sys.argv), I get the error output :

"['python/index.py']"

Which shows that my arguments are not correctly passed to my script.

I always get :

The command “python3 python/index.py” failed.

Exit Code: 1(General error)

Can someone explain to me why I get this?

Answer

The Python function sys.exit() is only intended to pass Python process exit status, not application results between processes. Call sys.exit(0) if the Python process terminated normally. Call sys.exit(1) or sys.exit("error-message-string") if there was an error. Your Python code passes a float to sys.exit() which evaluates to 1, causing Symfony Process to print the error message.

Instead, pass Python application results using print() to Symfony PHP. (See https://symfony.com/doc/3.4/components/process.html for several ways of getting the output of the Python process.)

Since $timeArray and $speedArray are arrays, passing them on the command line to Python is problematic because they may be treated as more than two arguments. So the below code passes the arrays as one JSON string.

Python script {symfony-base}/public/python/index.py) :

#!/usr/bin/python3

import json
import scipy.stats as stats
import sys

def kendallcoeff(x1,x2):
    tau, p_value = stats.kendalltau(x1,x2)
    return tau

print(sys.argv)
json_data = sys.argv[1]
python_obj = json.loads(json_data)
timeArray = python_obj[0]
speedArray = python_obj[1]

print(kendallcoeff(timeArray,speedArray))

sys.exit(0)

PHP Symfony class src/Controller/KendallCoefficientController.php should look something like this:

<?php

namespace AppController;
use SymfonyBundleFrameworkBundleControllerAbstractController;
use SymfonyComponentHttpFoundationResponse;
use SymfonyComponentProcessExceptionProcessFailedException;
use SymfonyComponentProcessProcess;
use SymfonyComponentRoutingAnnotationRoute;

class KendallCoefficientController extends AbstractController
{
    /**
     * @Route("/kendall", name="kendall")
     */
    public function index()
    {
        $timeArray = [1.0, 2.0, 3.0];
        $speedArray = [10.1, 20.2, 30.3];
        $arg = json_encode([$timeArray, $speedArray]);
        $process = new Process(['python3', 'python/index.py', $arg]);
        $process->run();

        // executes after the command finishes
        if (!$process->isSuccessful()) {
            throw new ProcessFailedException($process);
        }

        $pyoutput = $process->getOutput();

        $response = new Response($pyoutput, Response::HTTP_OK,
            ['content-type' => 'text/plain']);
        return $response;
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *