😽

【Python】例外処理把握によるエラーの特定

2023/03/27に公開

概要

システム開発に携わるデベロッパーであれば、誰しもデバッグに頭を悩ませることが多いだろう。特にデバッグするためのエラー内容特定について、時間がかかる人が多いのではないか。かく言う自分もそうである。システム開発歴が短いため、「これって、どう言うエラー??」とか「どこに原因があるの??」と問題分析ができず、時間を空費してしまうことが多々あった。コードを書くうえで、避けるべきエラー出力の方法と良いエラー出力の方法を記載する。

避けるべきエラー出力の方法

結論から言うと、下記が避けるべきエラー出力の方法である。

except:
	return json.dumps({
	    'success': False,
	    'error': "Error with creating a new drink"
	}), 500

なぜこの方法を避けるべきかというと、エラーが発生しても500エラーとしか表示されないからである。このような不明なエラーをデバッグするためには、例外処理の出力方法を改善する必要がある。具体的なエラーメッセージを表示することで、エラーの原因を特定しやすくなる。

良いエラー出力の方法

良いエラー出力の方法は下記である。

except Exception as e:
    return json.dumps({
        'success': False,
        'error': f"Error with creating a new drink: {str(e)}"
    }), 500

上記内容だと、exceptブロックで例外をキャッチして、その例外を変数eに代入してエラーメッセージを表示させている。そのため、問題が起こった時に、その問題の詳細情報を確認できるため、問題解決しやすくなる。

例外処理の一例

自分の場合、下記エラーが起こった際に、エラー特定に時間がかかっていた。やろうとしていることは、単純にbodyの内容をdrinkテーブルに対してPOSTするだけである。ただ問題が起こっても、500エラーとしか表示されないので、原因特定ができない。

@app.route('/drinks', methods=['POST'])
@requires_auth('post:drinks')
def post_drinks_detail(payload):
    body = {
        'id': 2, 
        'title': 'banana', 
        'recipe': [{'name': 'water', 'color': 'blue', 'parts': 1}]
        }
    try:
        id = body.get('id')
        title = body.get('title')
        recipe = json.dumps(body.get('recipe'))
        new_drink = Drink(id=id, title=title, recipe=recipe)
        print(new_drink)
        new_drink.insert()

        return jsonify({
            'success': True,
            'drinks': [new_drink.long()]
        }), 200
    except:
        return json.dumps({
            'success': False,
            'error': "Error with creating a new drink"
        }), 500

末尾に下記を追記したところ、具体的なエラー表示がされた。

except Exception as e:
    return json.dumps({
        'success': False,
        'error': f"Error with creating a new drink: {str(e)}"
    }), 500

エラー内容は、下記の通り。表示されたエラーによると、データベースの一意性制約が違反されたと示されている。具体的にはdrink.title列に一意性制約があり、既にwaterというタイトルが存在するため、同じタイトルを挿入しようとするとエラーが発生する。

{"success": false, "error": "Error with creating a new drink: (sqlite3.IntegrityError) UNIQUE constraint failed:
drink.title\n[SQL: INSERT INTO drink (id, title, recipe) VALUES (?, ?, ?)]\n[parameters: (2, 'water', '[{\"name\":
\"water\", \"color\": \"blue\", \"parts\": 1}]')]\n(Background on this error at: http://sqlalche.me/e/gkpj)"}

そのため、下記の通り問題解決できることがわかった。

  • 既存レコードを削除もしくは変更して、新しいレコードの追加を可能とする
  • 新しいレコードのタイトルを変更して、一意性制約を満たす
  • データベースのスキーマを変更して、一意性制約を削除または変更する

今後に向けて

下記の通り、例外処理エラーの詳細を表示して、その内容をchatGPTで聞くのが一番早い気がする。

except Exception as e:
    print(e)
    return json.dumps({
        'success': False,
        'error': f"Error with creating a new drink: {str(e)}"
    }), 500

Discussion