Python標準規格
このスキルは、Pythonツールおよびプロジェクト横断的なルールの信頼できる情報源です。アーキテクチャ、スタイル、テスト、レビューの各スキルは、このスキルを参照すべきであり、内容を重複して記述してはいけません。
プロジェクトの散文については、technical-writing も読み込んでください。technical-writing は humanizer を呼び出し、ドキュメントの場所、タイムスタンプ、レビューメタデータ、アクセシビリティ、および文章品質を管理します。
ルールの優先順位
以下の順序でルールを適用してください。
- ユーザーまたは組織の明示的な要件
- リポジトリの設定と承認されたアーキテクチャ上の決定
- このスキルおよびその他のPythonスキル
- PEP 8およびツールのデフォルト
セキュリティ基盤を黙って弱めてはいけません。必要な例外は、その範囲、リスク、判明している場合は責任者、および解除条件をプロジェクトの決定記録に記録してください。
ランタイムとレイアウト
- Python 3.11以降をターゲットにします。より新しいバージョンをターゲットとするリポジトリは尊重してください。
- 前方互換性を改善したり、アノテーションの順序問題を解決する場合には
from __future__ import annotationsを使用してください。必要のないファイルに機械的に追加しないでください。 - 新しい配布可能なパッケージには
src/レイアウトを推奨します。 - プロジェクトのメタデータとサポート対象のツール設定は
pyproject.tomlに保持してください。 - 環境、依存関係解決、ロック、コマンド実行には
uvを使用してください。
サポート対象ツールチェーン
| 目的 | デフォルト | 必須使用対象 |
|---|---|---|
| フォーマットとリンク | Ruff | すべてのメンテナンス対象プロジェクト |
| 型チェック | mypy (strict) | プロダクションパッケージと公開API |
| テストとカバレッジ | pytest, pytest-cov, coverage.py | すべての動作変更 |
| セキュリティリンク | Ruff SルールとBandit | プロダクションパッケージ |
| SAST | リポジトリルール付きSemgrep | メンテナンス対象製品のCI |
| 依存関係監査 | pip-audit | CIおよびリリースチェック |
| 構造化ログ | structlog | アプリケーションとサービス |
| トレーシング | OpenTelemetry | ネットワークサービスとトレース対象パイプライン |
| パッケージ管理 | uv | すべてのプロジェクト |
| Gitフック | pre-commit | メンテナンス対象リポジトリ |
| シークレット配信 | Infisical (組織デフォルト) | シークレットを使用するワークロード |
承認されたアーキテクチャ上の決定により、同等のベンダーを選択したり、小規模なローカルライブラリやスクリプトに適合しない運用ツールを省略することができます。Ruff、型チェック、テスト、および安全な依存関係管理はベースラインとして残ります。
モデルベースの脆弱性スキャナーやAIレビュアーを含む実験的なツールは助言的なもの(アドバイザリー)です。チームがサポート対象バージョン、コマンド、障害ポリシー、責任者を定義するまで、これらを必須ゲートにしてはいけません。
依存関係とバージョンポリシー
- 互換性のあるランタイム範囲を
pyproject.tomlで宣言してください。 - アプリケーションおよび再現可能な開発環境には
uv.lockをコミットしてください。ロックファイルが正確な解決済みバージョンを保持します。 - 公開ライブラリの場合、誠実な下限を宣言し、サポート対象のPythonバージョンと重要な下限をテストし、ロックファイルをコンシューマ契約として利用しないでください。
- 品質ツールとテストツールは名前付きの依存関係グループに配置してください。
- ロックされたuv環境を介して品質コマンドを実行してください。pre-commitで第二のPythonツールバージョンセットを管理しないでください。
- アップグレードは
uv lock --upgrade-package <name>またはレビュー済みの完全ロックリフレッシュによって意図的に行ってください。
uvプロジェクトにおける標準的な依存関係監査:
requirements_file="$(mktemp)"
trap 'rm -f "$requirements_file"' EXIT
uv export \
--frozen \
--no-dev \
--no-emit-project \
--no-hashes \
--format requirements.txt \
--output-file "$requirements_file"
uv run --frozen pip-audit \
--strict \
--no-deps \
--requirement "$requirements_file"
このエクスポートは、pip-auditに第二のグラフを解決させることなく、正確にロックされたランタイム依存関係を監査します。現在のpip-auditの --locked プロジェクト検出は pyproject.toml と pylock.*.toml をサポートしており、uv.lock はサポートしていないため、uv監査として pip-audit --locked . を使用しないでください。
pip-audit は品質依存関係グループに存在しなければなりません。脆弱性の適用除外(waiver)は、アドバイザリ、影響範囲、補完的制御、判明している場合は責任者、および有効期限または再レビュー日を明記しなければなりません。
標準品質コマンド
パッケージパスはリポジトリに合わせて調整してください。ただし、ローカル利用とCIで共通のコマンドソースを維持してください。
uv sync --frozen
uv run --frozen ruff check .
uv run --frozen ruff format --check .
uv run --frozen mypy <package-roots>
uv run --frozen bandit -c pyproject.toml -r <package-roots>
uv run --frozen semgrep scan --config .semgrep.yml <package-roots>
uv run --frozen pytest
# 上記の標準的なエクスポートロック依存関係監査を実行
CIはコマンドと結果を記録します。ツールまたは設定が見つからない場合は unavailable として記録し、合格として処理しないでください。
Pre-commitの所有権
非Pythonの衛生フックはリリースで固定してください。Python品質ツールは、uv run --frozen を使用してローカルフックとして呼び出し、ローカルフックとCIが uv.lock の正確なバージョンを使用するようにします。
repos:
- repo: local
hooks:
- id: ruff-check
name: ruff check
entry: uv run --frozen ruff check --fix
language: system
types_or: [python, pyi]
- id: ruff-format
name: ruff format
entry: uv run --frozen ruff format
language: system
types_or: [python, pyi]
- id: mypy
name: mypy
entry: uv run --frozen mypy
language: system
pass_filenames: false
args: [<package-roots>]
Bandit、Semgrep、テスト、依存関係監査はCIで実行してください。レイテンシと依存関係がリポジトリに適合する場合にのみ、pre-commitに追加してください。
最小限の pyproject.toml 設定
プレースホルダをコピーするのではなく、リポジトリのパッケージ名とルートを使用してください。
[tool.ruff]
line-length = 88
target-version = "py311"
[tool.ruff.lint]
select = ["E", "F", "I", "N", "W", "B", "S", "UP", "C4", "SIM", "RUF", "D"]
ignore = ["E501"]
[tool.ruff.lint.pydocstyle]
convention = "google"
[tool.mypy]
python_version = "3.11"
strict = true
warn_return_any = true
warn_unused_configs = true
ignore_missing_imports = false
[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "-ra --strict-markers --tb=short --import-mode=importlib"
[tool.coverage.run]
branch = true
source_pkgs = ["your_package"]
[tool.coverage.report]
fail_under = 80
show_missing = true
[tool.bandit]
exclude_dirs = ["tests"]
skips = ["B101"]
すべての無視(ignore)は、限定的な範囲と理由を文書化してください。グローバルな無視よりもファイル単位の無視を推奨します。
構造化ログ契約
アプリケーションは以下のフィールドを出力します。ライブラリはホストアプリケーションのログファサードを使用してもよく、インポート時にグローバルハンドラを設定してはいけません。
| フィールド | 要件 | 意味 |
|---|---|---|
timestamp | 常に | ISO 8601 UTC |
level | 常に | DEBUG、INFO、WARNING、ERROR、または CRITICAL |
event | 常に | 安定したスネークケースのイベント名 |
service | アプリケーションでは常に | サービス名またはアプリケーション名 |
trace_id | トレースが存在する場合 | OpenTelemetry トレースID |
span_id | スパンが存在する場合 | OpenTelemetry スパンID |
error | 障害時 | 安全な例外タイプとメッセージ |
duration_ms | 計測対象の操作時 | 経過ミリ秒 |
Structlogのレベルプロセッサは一般的に小文字のメソッド名を受け取ります。レベル追加後に正規化してください。
from typing import Any
import structlog
def uppercase_log_level(
_logger: Any,
_method_name: str,
event_dict: dict[str, Any],
) -> dict[str, Any]:
"""構造化ログレベルを共有スキーマに正規化します。"""
level = event_dict.get("level")
if isinstance(level, str):
event_dict["level"] = level.upper()
return event_dict
processors = [
structlog.processors.add_log_level,
uppercase_log_level,
structlog.processors.TimeStamper(fmt="iso", utc=True),
]
プロセッサ単体だけでなく、最終的にレンダリングされたイベント全体をテストしてください。
セキュリティ基盤
絶対に行ってはいけないこと:
- 認証情報、トークン、秘密鍵、または実際のシークレット値をコミットまたはハードコードすること
- 実際のシークレットを
.envやTOMLファイルに保存すること - シークレット、アクセストークン、機密性の高い個人データ、または無制限のリクエストボディをログに記録すること
- SQLに外部の値を補間すること
- 外部入力または変数入力と共に
shell=Trueを使用すること - 信頼できないpickleデータをデシリアライズすること
- 信頼できない入力を
eval、exec、またはcompileで実行すること - 可変デフォルト引数を使用すること
- 文書化されたパブリック再エクスポートを除き、ワイルドカードインポートを使用すること
- セキュリティに敏感な戻り値や例外を静かに無視すること
- ベア
except:を使用すること
Exception のキャッチは、プロセス、ワーカー、タスク、またはフレームワーク境界でのみ行い、そこでハンドラが安全にログを記録し、再 raise するか、障害を終了ステータスにマッピングするか、定義されたプロトコルエラーを返すようにしてください。アプリケーションロジック内では特定の例外をキャッチしてください。
通常の設定とシークレット参照は設定ファイルに保存してください。起動時にInfisicalインジェクションまたは承認された同等の方法を通じてシークレット値を配信してください。作業を受け入れる前に、必要な設定がすべて揃っていることを検証してください。