0

I want to run a Python script test.py from my Laravel controller, where the script imports a Python module. At first I was getting a module not found error for the python package I import into the python script after testing that the python script worked without it. I am using Laravel Sail and WSL2. If I make the test.py script the following:

import sys
    
print(sys.path)

and run in my controller this:

$process = new Process(['python3', app_path('Http/Controllers/test.py'), $content]);
$process->run();

if (!$process->isSuccessful()) {
    throw new ProcessFailedException($process);
}

$result = $process->getOutput();
$path = public_path('temporary/helloworld.txt');
file_put_contents($path, $result);

then it works and the output file has:

['/var/www/html/app/Http/Controllers', '/usr/lib/python39.zip', '/usr/lib/python3.9', '/usr/lib/python3.9/lib-dynload', '/usr/local/lib/python3.9/dist-packages', '/usr/lib/python3/dist-packages']

However if I change the python script to one that imports the Python module, I get a module not found error ("No module named .."), even though the module is installed to the virtual environment. So I tryed navigating to the root of my project, and I execute 'source tutorial-env/bin/activate' to activate the python virtual environment. Then I do 'python' 'import sys' 'print(sys.path)' and get:

 ['', '/usr/lib/python38.zip', '/usr/lib/python3.8', '/usr/lib/python3.8/lib-dynload', '/home/username/project-name/tutorial-env/lib/python3.8/site-packages']

So I am pretty sure the problem was the laravel app using the wrong Python path. So I change in my laravel controller to this:

$process = new Process(['source ' . base_path('tutorial-env/bin/activate') . ' && python3', app_path('Http/Controllers/test.py'), $content]);
$process->run();

if (!$process->isSuccessful()) {
    throw new ProcessFailedException($process);
}

Then I get the error: The command

"'source /var/www/html/tutorial-env/bin/activate && python3' '/var/www/html/app/Http/Controllers/test.py' 'some text'" failed. Exit Code: 127(Command not found) Working directory: /var/www/html/public Output: ================ Error Output: ================ sh: 1: exec: source /var/www/html/tutorial-env/bin/activate && python3: not found

3 Answers3

0

I think you can do something like this in a controller or better in a service :

// src/Controller/monSuperController.php ou mieux dans un service

// use Symfony\Component\Process\Exception\ProcessFailedException;
// use Symfony\Component\Process\Process;

// (...)
$process = new Process(
    [
        '/home/User/path-with-my-python-script/env/bin/python3', 
        '/home/User/path-with-my-python-script/myPythonScript.py',
        '--path', '/home/User/file-path-for-my-python-script/file-for-my-python-script.csv', 
        '--opt1', '1', 
        '--opt2', 'n'
    ]
);


$process->run();
    
// executes after the command finishes
if (!$process->isSuccessful()) {
    throw new ProcessFailedException($process);
}
//you can add a timeout, deactivate python env, kill the process etc in the same way. Have a nice day

// (...)
0

I found the Process class' virtual env was using the wrong version of Python - changing the command to python3 solved the module import problem for me.

Rich
  • 553
  • 1
  • 10
  • 20
-1

You might have to specify every part of the command as an array value, like so:

$process = new Process(
    [
        'source',
        base_path('tutorial-env/bin/activate'),
        '&&',
        'python3',
        app_path('Http/Controllers/test.py'),
        $content,
     ]
 );

...also python instead of python3 should also do the trick in a virtual environment.

gherkins
  • 14,603
  • 6
  • 44
  • 70