DatabricksでPythonデバッガー(pdb)を使う

以下の記事を訳していた時に気づきました。Python debugger(pdb)を使うことで、例外発生時の問題特定が容易になります。

https://qiita.com/taka_yayoi/items/d21eda71037575dcaf7d

翻訳済みサンプルノートブックはこちらです。

https://github.com/taka-yayoi/public_repo_2/blob/master/python_debugger/Debugging%20Examples.py

# 要件

Databricksランタイム11.2以降が必要となります。

# サンプルノートブックのウォークスルー

Databricksノートブックにおけるpdbの使い方のサンプルを示します。
- 最後の例外からデバッグするには`%debug`を使います。これは、予期しないエラーに遭遇し、原因をデバッグする際に役立ちます(`pdb.pm()`と似ています)。
- 例外後(しかし、プログラム終了前)にインタラクティブなデバッガーを自動で起動するには`%pdb on`を使います。

これらのコマンドを使う際には、他のセルを実行する前にデバッガーの使用を停止する必要があることに注意してください。デバッガーを終了する方法はいくつかあります。
- 実行中のセルを終了するために`c`あるいは`continue`を入力
- エラーをスローしコード実行を停止するために`exit`を入力
- 出力ボックスの隣にある`Cancel`をクリックしてコマンドをキャンセル

## `%debug` : 事後のデバッグ
Databricksノートブックで`%debug`を使うには:
1. 例外が起きるまでノートブックのコマンドを実行します。
2. 新規セルで `%debug` を実行します。セルの出力エリアでデバッガーが動作を始めます。
3. 変数を調査するには、入力フィールドに変数名を入力し **Enter** を押します。  
4. 以下のコマンドを用いることで、変数の調査の様に、コンテキストを切り替えたり他のデバッガータスクを行うことができます。デバッガーの完全なコマンドの一覧に関しては、[pdb documentation](https://docs.python.org/3/library/pdb.html)をご覧ください。文字列を入力し、 **Enter** を押します。  
   - `n`: 次の行
   - `u`: 現在のスタックフレームを抜けて1レベル上に移動
   - `d`: 現在のスタックフレームを抜けて1レベル下に移動
5. このノートブックの最初のセルで説明した方法のいずれかでデバッガーを抜けます。

```py:Python
class ComplexSystem1:
  def getAccuracy(self, correct, total):
    # ...
    accuracy = correct / total
    # ...
    return accuracy
  
class UserTest:
  def __init__(self, system, correct, total):
    self.system = system
    self.correct = correct
    self.total = 0 # 間違った合計を設定しています！
    
  def printScore(self):
    print(f"You're score is: {self.system.getAccuracy(self.correct, self.total)}")
  
test = UserTest(
  system = ComplexSystem1(),
  correct = 10,
  total = 100
)

test.printScore()
```

上のセルを実行すると例外が発生します。
![Screen Shot 2022-11-05 at 8.13.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/fd844f87-6c5c-9e00-d3af-cd500fff8604.png)

デバッガーを起動します。
```
%debug
```

![Screen Shot 2022-11-05 at 8.18.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/f652004d-23a1-318a-2a18-ea2c8679d674.png)

こちらにコマンドを入力していきます。
![Screen Shot 2022-11-05 at 8.18.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/d9f2bad4-1e85-c0c1-f0ed-a525178e7f2a.png)

`total`が`0`であることがわかります。
![Screen Shot 2022-11-05 at 8.19.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/351cf498-7306-0cb5-e5ce-e8f346a41423.png)

スタックトレースを1レベル上に上がります。
![Screen Shot 2022-11-05 at 8.20.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/e3bbadb3-3248-7eab-9d9a-90d108a72559.png)

`self.total`を確認すると`0`であることがわかるので、これが原因であることが判明しました。
![Screen Shot 2022-11-05 at 8.20.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/46cdf6e0-1ac1-154f-23b9-7fd3badabda9.png)

`c`でデバッガーから抜けます。
![Screen Shot 2022-11-05 at 8.21.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/b08750c8-699c-37ef-c717-e6bdce4f8417.png)

## `%pdb on` : 事前のデバッグ

Databricksノートブックで`%pdb on`を使うには:
1. ノートブックの最初のセルで`%pdb on`を実行して自動pdbをオンにします。
1. 例外が起きるまでノートブックでコマンドを実行します。インタラクティブなデバッガーが起動します。
1. 変数を調査するには、入力フィールドに変数名を入力し **Enter** を押します。
1. 以下のコマンドを用いることで、変数の調査の様に、コンテキストを切り替えたり他のデバッガータスクを行うことができます。デバッガーの完全なコマンドの一覧に関しては、[pdb documentation](https://docs.python.org/3/library/pdb.html)をご覧ください。文字列を入力し、 **Enter** を押します。  
   - `n`: 次の行
   - `u`: 現在のスタックフレームを抜けて1レベル上に移動
   - `d`: 現在のスタックフレームを抜けて1レベル下に移動
1. このノートブックの最初のセルで説明した方法のいずれかでデバッガーを抜けます。

pdbをオンにします。

```
%pdb on
```
![Screen Shot 2022-11-05 at 8.22.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/76947bfb-abe3-16f2-0970-9233121e742d.png)

```py:Python
class ComplexSystem2:
  def getAccuracy(self, correct, total):
    # ...
    accuracy = correct / total
    # ...
    return accuracy

system = ComplexSystem2()

## テストのカバレッジ
print("Tests")
print(system.getAccuracy(10, 100) == 0.1)
print(system.getAccuracy(10, 0), 0)
```

例外が発生すると、自動でデバッガーが起動します。
![Screen Shot 2022-11-05 at 8.23.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/7c78f2ef-558b-89d8-c5a3-96ed69bf8635.png)

上と同じ様にデバッグすることができます。
![Screen Shot 2022-11-05 at 8.25.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/56716d54-bd7b-93e4-9441-0e53e9b14ff8.png)

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)