使用 Symfony Process 从 Laravel 控制器运行 Python 脚本遇到困难

问题描述 投票:0回答:4

我想从我的 Laravel 控制器运行 Python 脚本 test.py,该脚本在其中导入 Python 模块。起初,在测试 python 脚本在没有它的情况下也能正常工作后,我导入到 python 脚本中的 python 包出现了模块未找到错误。我正在使用 Laravel Sail 和 WSL2。如果我将 test.py 脚本设为以下内容:

import sys
    
print(sys.path)

并在我的控制器中运行:

$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);

然后它就可以工作并且输出文件有:

['/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']

但是,如果我将 python 脚本更改为导入 Python 模块的脚本,即使该模块已安装到虚拟环境中,我也会收到找不到模块的错误(“没有名为 ..”的模块)。因此,我尝试导航到项目的根目录,然后执行“sourcetutorial-env/bin/activate”来激活 python 虚拟环境。然后我执行 'python' 'import sys' 'print(sys.path)' 并得到:

 ['', '/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']

所以我很确定问题是 Laravel 应用程序使用了错误的 Python 路径。所以我将我的 Laravel 控制器更改为:

$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);
}

然后我收到错误:命令

"'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
laravel virtualenv symfony-process
4个回答
1
投票

我认为你可以在控制器中做这样的事情,或者在服务中做更好的事情:

// 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
投票

我发现 Process 类的虚拟环境使用了错误版本的 Python - 将命令更改为

python3
解决了我的模块导入问题。


0
投票

问题大概是这样的:

sh: 1: exec: source /var/www/html/tutorial-env/bin/activate && python3: not found

在 Ubuntu 中,默认的 sh 不是 bash 或 sh,而是 dash(/bin/sh 链接到 /bin/dash),并且 dash shell 没有命令“source”。在达世币中,这是“.”。这也适用于 bash 和 sh。您从控制器获得不同结果的原因可能是因为控制器从其启动的网络服务器(在本例中为 laravel/sail)继承了 shell。 Laravel sail 命令使用 bash 和 envs 定义的 #!/usr/bin/env bash. 如果您将进程放入命令中并使用

运行
sail artisan <command>

然后您应该获得与在控制器中运行相同的行为。

另一个选项是切换默认 shell:

sudo dpkg-reconfigure dash

但这不仅会取代您的进程的破折号,还会取代整个系统的破折号,这意味着所有命令都默认为 bash,即使它们是在后台执行的。很多时候 bash 具有针对终端和其他功能的可视化定制,例如最初加载的完成,这可能会减慢执行速度。

$process = new Process(['source ' . base_path('tutorial-env/bin/activate') . ' ...

理论上这应该可行

$process = new Process(['. ' . base_path('tutorial-env/bin/activate') . ' &&

-1
投票

您可能必须将命令的每个部分指定为数组值,如下所示:

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

...另外

python
而不是
python3
也应该在虚拟环境中发挥作用。

© www.soinside.com 2019 - 2024. All rights reserved.