概要
結論を書くと特ににひねりのない話ですが
- 名前がついているなど、そのレイアウトだと特定の手段があること
- Web上にガイドラインがあること
- (あればうれしい) テンプレートを配置したレポジトリや、生成コマンドがあること
を条件にしました。
結果、以下になりました。
- フレームワーク未使用のもの
-
uvの--packageレイアウト (参照) ( PyPA の src レイアウト)
-
- フレームワークを使用するもの
- フレームワークのリファレンスに従う
以下、条件の選定理由と、調べたことについて記載していきます。
条件の選定理由
条件として以下の2つ+1つを挙げました。
- 名前がついているなど、そのレイアウトだと特定の手段があること
- Web上にガイドラインがあること
- (あればうれしい) テンプレートを配置したレポジトリや、生成コマンドがあること
まず、必須の2つは短い内容でパターンが特定できて、具体も分かり、人/生成AIともに説明の効率がよいという理由です。
独自仕様だと説明ドキュメントが必要になりますし、エッジケースというほどでもない内容でも確認が必要になる場合があります。また、広く使われている語であっても用例によってブレが多かったり、同じ名前でも違うパターンがある場合もやや使いづらいです(パターンが明確に分かれていれば「〇〇の△△パターン」と指定すればよいですが)。
なのでできるだけ
- 提供元が提示している内容がある
- (あればうれしい) テンプレートを配置したレポジトリや生成コマンドがある
とよいということになります。
フレームワーク未使用のもの
私のこの用途はチームで利用する IaaS/SaaS を対象とした運用スクリプトです。ライブラリを使ったり、要所はテストを書いておきたいという、シェルスクリプトより複雑なことを利用したいという用途です。
フレームワーク未使用の場合、Python Package Authority (PyPA) のガイドに沿うのがよいかと思ったので、PyPA のガイドを参照することにしました。
PyPA のガイド中にちょうどその内容がありました。
ここで pypa/pipx で実行可能な配布 CLI を作るさいのレイアウトが記載されており、 src-layout を使うことが記載されています。
ガイド中の記載レイアウトは以下です。
.
├── pyproject.toml # プロジェクトメタデータ。CLIエンドポイントの指定もする
└── src
└── greetings
├── cli.py # フラグのパースなどのCLI用の処理
├── greet.py # 実際の処理
├── __init__.py # パッケージ名前空間用
└── __main__.py # CLI のエントリポイント配置
ガイド中では単体テスト用のディレクトリは省略されていますが、 src/ と同じ高さに tests/ を配置することになると思います( __init__.py 付きで)。
併せてみると以下でしょうか
.
├── pyproject.toml
├── src
│ ├── greetings
│ │ ├── cli.py
│ │ ├── greet.py
│ │ ├── __init__.py
│ │ └── __main__.py
├── tests
│ ├── test_greet.py
│ ├── __init__.py
│ └── ...
└── ...
現在のプロジェクトでは uv を使っているので
- スケルトンコードの生成は uv init --pacakge ${package_name} で作成
- テスト中のローカル動作や、一時利用は uvx [--from ${source}] ${pacakge_name} で実行
で対応しています。
用途としてよいかは少し微妙な部分もあるのですが、GitHub に配置して
uvx --from git+https://github.com/${org}/${repo}@${version_tag} ${package_name}
でサッと試してもらったりできるようにしています。
また、あくまで社内用途なので PyPI にアップロードするための内容は対応していません。
フレームワークを使用するもの
PyPA の概要にフレームワークを利用する場合の話が書いてあります。
私の解釈込みですが、「フレームワーク側での決定があるものに関してはそれなりの背景事情があるので、フレームワークの規定に従うメリットがある」という理解です。
Python のフレームワークで利用しているのは FastAPI が多いので、公式に記述があるか調べてみました。
以下あたりが対象かなとは思うのですが
明記あるのはルーティング回りだけ(API作成のフレームワークの責務がそこであるのは確かですが)で、後は構成ベースでグルーピングするか、機能ベースでグルーピングするかは選択する必要があると思います。FastAPI の公式の方はサブディレクトリが routes と internal しかないのでどっちとも言いづらいですが。
正直ここは個別にルール決めてかかないといけないのかなと思いました。
に両案載ってましたが、場合によるかなという印象です。プロジェクト個別でこうするという決めが必要そうでした。
おわりに
Python のプロジェクトレイアウトの見直しを考えてみたのですが、思ったほど具体は決まっていなくてプロジェクトの状況で決めて行かないとなという結論になりそうでした。