寝ている時に異常を知らせる通知音を出させる

実行に時間がかかる処理を行うなら、夜寝たりとか別作業をしたりしたい。
そうなると、いつの間にか処理が失敗しており、気づくまでの間の時間がタイムロスになったりすることが度々ある。
そこでPythonで何か異常を検知したら警告音を出してくれるような仕組みを作りたい。
それも、なるべく再利用できるような形にしておきたいのと、汎用的にしたい。

テキトーに警告音となるMP3ファイル(今回はkeikoku01shibu.mp3)を用意する。
デコレータでラッパー関数を作り、ラッパーされる処理が特定の条件を満たしたり、例外が発生したらその警告音を出すようにする。
```python
from playsound import playsound

def watch_allert_with_args(arg = None):
    def watch_allert(func):
        def _watch_allert(*args, **kwargs):
            path = 'sounds/keikoku01shibu.mp3'
            try:
                result = func(*args, *kwargs)
                if (result == arg) or\
                    ((arg is not None) and (hasattr(arg, "__iter__")) and (result in arg)):
                    print("警告: 条件が満たされました！result:",result)
                    # 警告音を再生する
                    playsound(path)
            except Exception as e:
                print("警告: 条件が満たされました！", e)
                # 警告音を再生する
                playsound(path)
        return _watch_allert
    return watch_allert
```
ちなみに```playsound```をインストールして普通に使おうとすると、Python3に対応していないらしく、追加で```PyObjC```をインストールする必要があった。

使い方は例えば以下のようになる。
以下は二次方程式$x^2-2x+3=0$の実数解を求めるためのsample関数だが、この方程式に実数解は存在しない。
解がなかったら(つまり```result == []```のとき)警告音を出したいので```@watch_allert_with_args([])```のようにして```[]```を引数に持たせている。
```python

@watch_allert_with_args([])# resultが空になったら警告を出す
def sample():
    # 二次方程式x^2 -2x + 3 = 0の実数解を求める。(実数解はないため警告を出す)
    x = sympy.Symbol('x', real=True)
    result=sympy.solve(x**2 - 2 * x + 3)
    return result

if __name__ == "__main__":
    sample()
```
以下はまた別の例である。
この関数は、整数0で整数を割ることによる例外が発生する。
この例外を検知し警告音が鳴る。
```Python
@watch_allert_with_args()
def sample():
    # 100を10から-10までの整数で割り続けて更新していく処理(0で割る時に例外が発生し警告音が出る)
    sum = 100
    for i in range(10,-10,-1):
        sum /= i
    return sum

if __name__ == "__main__":
    sample()
```
こんな感じで、長時間実行したい関数などにラッパー関数で監視させておくことができる。

Google Colaboratoryではなぜかplaysoundが使えなかった(playsoundを使うために必要なモジュールのimportがsubprocessの問題でできなかった)ため、displayとAudioで代用した。
逆にPythonスクリプトの方でもdisplayとAudioを使って警告音を出すようにして仕組みを統一したかったが、displayとAudioはnotebookのセルでないと音が出せなかった。
(Pythonスクリプトでもnotebookでも同じように音を出すような方法はないだろうか？自分でラッパー関数を作らないといけない？)
```python
from IPython.display import Audio, display

def watch_allert_with_args(arg = None):
    def watch_allert(func):
        def _watch_allert(*args, **kwargs):
            path = "/content/drive/MyDrive/sounds/keikoku01shibu.mp3"
            try:
                result = func(*args, *kwargs)
                if (result == arg) or\
                    ((arg is not None) and (hasattr(arg, "__iter__")) and (result in arg)):
                    print("警告: 条件が満たされました！result:",result)
                    # 警告音を再生する
                    display(Audio(path, autoplay=True))
            except Exception as e:
                print("警告: 条件が満たされました！", e)
                # 警告音を再生する
                display(Audio(path, autoplay=True))
        return _watch_allert
    return watch_allert
```

まあこんなようにして、対象となる関数が特定の値を返したり、特定のイテラブル変数に含まれたり、例外を発生させたりする場合には警告音を出させて気付けるようにはできた。
ただしVSCodeのブレークポイントの条件文みたいな柔軟さは実現できていない。
あとは警告音を出すといっても、今はちょっとした音声でしかないので、眠りが深かったりしたら気付けないかもしれない。単純にMP3ファイルの音声を流したりするのではなく、意識的に止めない限り鳴らし続けたり、YouTubeとかから緊急地震速報の動画を流したりするのも良いかもしれない。
そこら辺はまだ課題としつつも、ひとまず当座の目的は達成できたからよしとしよう。