Laravel sailでPythonを使う

自作のポートフォリオをLaravelで制作中にPythonのライブラリを使って処理を実行したかったので、挑戦してみました。
いくつかのつまづきポイントがあったのでまとめ

## 開発環境
 PHP(8.0.2)
 Laravel(9.19)
 Python(3.8.10)

### Pythonの実行はexec関数
PythonをLaravel上で使用するのに、いろいろ調べたところ、PHPのexec関数で実行できるということでした。
まずはPythonファイルを作成。
私はappディレクトリ内にpythonディレクトリを作りその中にファイルを作りました。

```python
import sys
import pandas_datareader.data as web

code = sys.argv[1]+'.T'
start_date = sys.argv[2]
start_open_or_close = sys.argv[3]
end_date = sys.argv[4]
end_open_or_close = sys.argv[5]

df = web.DataReader(code, 'yahoo', start_date, end_date)

start_price = df.loc[start_date,start_open_or_close]
end_price = df.loc[end_date,end_open_or_close]
yield_price = end_price - start_price
yield_ratio = round(yield_price/start_price*100,1)
high = df['High'].max()
low = df['Low'].min()
print(start_price)
print(end_price)
print('{:+}'.format(yield_price))
print('{:+}'.format(yield_ratio))
print(high)
print(low)
```

今回はpandas_datareaderライブラリを使って、コードと日付を受け取り、株価等を返したかったので、
①ライブラリをインポート
②sys関数で引数をとる
③実行メソッドを書く
④print関数で出力
を行いました。

そしてLaravelのControllerでexec関数を使いPythonファイルを実行し、返ってきた値をsessionに入れています。

```php
    public function start(Request $request)
    {
        $request->validate([
            'code' => 'required | numeric',
            'start_date' => 'required | date | before_or_equal:today |  before_or_equal:end_date',
            'end_date' => 'required | date | before_or_equal:today | after_or_equal:start_date',
	    ]);

	    $path = app_path() . "/python/test.py";
        $code = $request->code;
        $star_date = $request->start_date;
        $start_open_or_close = $request->start_open_or_close;
        $end_date = $request->end_date;
        $end_open_or_close = $request->end_open_or_close;
        $command =  "/usr/bin/python3 " . $path . " $code" . " $star_date" . " $start_open_or_close" . " $end_date" . " $end_open_or_close";
	    exec($command, $output);

        if (empty($output)){
            return back()->withInput()->with('no_data', '銘柄コード、日付を正しく入力してください');
        }
        $result = [
            'start_price' => $output[0] ,
            'end_price' => $output[1] ,
            'yield' => $output[2] ,
            'yield_ratio' => $output[3] ,
            'high' => $output[4] ,
            'low' => $output[5] ,
        ];
        $inputs = $request->except('_token');

        $request->session()->put($inputs);
        $request->session()->put($result);

        return view('analyze.result');
    }
```

これで銘柄コードと日付を渡せば株価や暴落率が返ってくる。
問題はここからです。

### pip問題
ローカル環境では動作するのに、コンテナ内では上手く返ってこない。
原因はLaravel sailのdockerコンテナ内にpythonはインストールされているものの、pipがインストールされていなかった。
そこでコンテナ内に入ってpipをインストールしようとしました。

```
sail shell
```

そこでaptを実行しようとしても権限エラー

```
sail root -shell
```
でルートユーザーでログインできたので、
```
apt update
apt upgrade
apt install pip
```
で解決。
そして必要なライブラリをpipインストール

### docker fileの編集
コンテナ内で直接pipとライブラリをインストールしてもコンテナを停止して再開したら消えています。

そこでdocker fileを編集しました。
```
sail artisan sail:publish
```
でルートディレクトリにdockerファイルの入ったディレクトリが出現。

そこにapt-getのところにpipを追加。

さらに、
```
RUN pip install ライブラリ名
```
を追加。

```
sail build --no-cache
```
でコンテナを再構築すれば、毎回コンテナに入ってインストールしなくて済みました。

### aws内でのエラー
awsにデプロイする際にもつまづきがありました。
デプロイ後値がなにも返ってこない。
ひも解いていくと、PythonファイルでModuleNotFoundErrorとなっていました。
pipインストールしてpip listで確認してもインストールされているのに。

どうやらimportする際の探しにいくpathが問題のようで、
sudoをつけてpipインストールすると解決しました。
これについてももう少し調査の必要があります。

## まとめ
言語の組み合わせはなかなか情報が少なくて難しい。
なかなかハードルが高く、無理やりな部分もありますが勉強になりました。