
Python や Django のバージョンアップデートは、新機能の利用や脆弱性対策のために欠かせない作業です。しかし、非推奨になった API の洗い出しや、新しい構文への書き換えを手動で行うのは骨が折れます。本記事では、アップデート作業の効率化に役立った3つのツールを紹介します。
背景
Python や Django のアップデートを行う際は、既存のコードが新しいバージョンでも動作するかを確認するだけでなく、非推奨となった機能や古い記法を使用している箇所を洗い出すことも重要です。非推奨機能は将来のバージョンで削除される可能性があり、古い記法は新しい書き方に置き換えることでコードの可読性や保守性の向上につながります。
このような作業を手作業で行うと、見落としが発生しやすく、時間もかかります。自動的にコードをチェックし、問題が見つかった場合に修正を提案・実施してくれるツールを活用することで、作業時間を短縮し、人的ミスを防ぐことができます。
以下では、実際のアップデート作業で役立ったツールを紹介します。
Ruff
Ruff は Rust で実装された、非常に高速な Python リンターおよびコードフォーマッターです。既存のリンター(Flake8 など)やフォーマッター(Black など)と比較して、10〜100倍高速に動作します。
pyupgrade ルールの活用
Ruff には pyupgrade (UP) というルールセットが含まれています。このルールセットは、古い Python の記法を新しいバージョンの記法に自動的に変換します。
今回のプロジェクトでは、以下のようなルールが検出されました。
- PEP 585 に準拠しない型アノテーション(
typing.List→listなど) - PEP 604 に準拠しない Union や Optional の記法(
Union[str, int]→str | intなど) - PEP 695 に準拠しない型エイリアスやジェネリックの定義
- 非推奨のインポート
- UTC タイムゾーンの古い記法
以下のコマンドで pyupgrade ルールに違反している箇所をチェックできます。
uv run -m ruff check --select=UP
--fix オプションを追加することで、自動修正も可能です。
uv run -m ruff check --select=UP --fix
banned-api ルールの活用
Ruff の banned-api (TID251) ルールを使用すると、特定の API の使用を制限できます。今回は、Django 4.0 のタイムゾーン実装変更への対応や、Python 3.12 および Python 3.13 で削除されたモジュールを検出するため、このルールを活用しました。
Django 4.0 以降、Python 標準ライブラリの zoneinfo がデフォルトのタイムゾーン実装となり、pytz から zoneinfo への移行が推奨されています。以下の設定では、バージョンアップデートに伴い使用を避けるべきタイムゾーン関連の API や削除されたモジュールを検出できるようにしています。
[tool.ruff.lint.flake8-tidy-imports.banned-api] "datetime.timezone".msg = "Use zoneinfo.ZoneInfo instead of datetime.timezone." "django.utils.timezone.datetime".msg = "Use datetime.datetime instead of django.utils.timezone.datetime." "django.utils.timezone.make_aware".msg = "Use datetime.datetime.replace instead of django.utils.timezone.make_aware." "django.utils.timezone.timedelta".msg = "Use datetime.timedelta instead of django.utils.timezone.timedelta." "django.utils.timezone.timezone".msg = "Use zoneinfo.ZoneInfo instead of django.utils.timezone.timezone." "django.utils.timezone.tzinfo".msg = "Use datetime.tzinfo instead of django.utils.timezone.tzinfo." "pytz.timezone".msg = "Use zoneinfo.ZoneInfo instead of pytz.timezone." "pytz.UTC".msg = "Use datetime.UTC instead of pytz.UTC." "pytz.utc".msg = "Use datetime.UTC instead of pytz.utc." "distutils".msg = "distutils is removed in Python 3.12 (PEP 632)." "django.utils.timezone.utc".msg = "Use datetime.UTC instead of django.utils.timezone.utc." "imghdr".msg = "imghdr is removed in Python 3.13 (PEP 594)."
以下のコマンドで banned-api ルールに違反している箇所をチェックできます。
uv run -m ruff check --select=TID251
この設定により、pytz から zoneinfo への移行が必要な箇所や、Python の新バージョンで削除されたモジュールの使用を効率的に検出できました。
mypy
mypy は Python の静的型チェッカーです。型アノテーションを使用したコードの型安全性を検証するだけでなく、非推奨となった機能の使用も検出できます。
非推奨コードの検出
mypy の --enable-error-code=deprecated オプションを使用すると、非推奨となった API やメソッドの使用箇所を検出できます。この機能は、Python や使用しているライブラリのバージョンアップデートで特に有用です。
uv run -m mypy --enable-error-code=deprecated .
このコマンドを実行することで、将来のバージョンで削除される可能性のある機能を事前に特定し、代替手段への移行に役立てることができます。
django-upgrade
django-upgrade は Django のコードを最新のバージョンに対応させるためのツールです。Django 特有の非推奨機能や古い記法を新しいものに自動的に書き換えてくれます。
使用方法
django-upgrade は、ファイル単位で動作するツールです。プロジェクト全体をアップデートする場合、すべての Python ファイルを対象とする工夫が必要です。以下のコマンドは、Git で管理されているすべての Python ファイルに対して django-upgrade を適用します。
git ls-files -z -- '*.py' | xargs -0r uvx django-upgrade
バージョンの自動検出
django-upgrade の便利な機能の1つに、ターゲットバージョンの自動検出があります。--target-version オプションを指定しない場合、カレントディレクトリの pyproject.toml を探します。見つかった場合、project.dependencies からサポートする最小の Django バージョンを自動的に解析します。django>=5.2,<6.0 のような一般的な依存関係の記法に対応しているため、プロジェクトごとにコマンドを変える必要がありません。
もし pyproject.toml が見つからない場合や、Django のバージョンを検出できない場合は、デフォルトで Django 2.2 をターゲットとします。このような場合は、明示的に --target-version オプションを指定することをおすすめします。
まとめ
Python や Django のアップデート作業において、これらのツールを活用することで、手作業によるミスを減らし、効率的にプロジェクトのコードを最新の状態に保つことができました。
- Ruff の pyupgrade ルールで古い Python の記法を新しいバージョンの記法に変換し、banned-api ルールでプロジェクト固有の API 使用を制限する
- mypy で非推奨 API の使用箇所を検出する
- django-upgrade で Django 特有の非推奨機能を自動修正する
今回はこれらのツールを CI/CD パイプラインにも組み込むことで、並行開発されている機能を取り込む際に古い記法や非推奨 API を自動検出できるようになり、対応漏れの防止につなげることができました。今回紹介したようなツールの活用が、Python や Django のアップデートを検討されている方の参考になれば幸いです。
ビザスクではエンジニアの仲間を募集しています! 少しでもビザスク開発組織にご興味を持たれた方は、ぜひ一度カジュアルにお話ししましょう! recruit.visasq.co.jp