自分で書いたコードをpipでインストールできるようにするためにはパッケージ化する必要があります。その作成手順をまとめてみました。
*.whl形式のファイルを作る。これさえあれば
pip install xxxx.whl
これでインストールできます。これを作ります。
新しい仮想環境を作る
必ずしも必要な手順ではありませんが、自作ライブラリの依存関係をはっきりさせるために、新規の環境を作成しそこで作業します。
python -m venv "なにがしか"
これで空っぽの”なにがしか”という名前の環境ができます。その環境で作業します。
/Script/activate
これでアクティベートされます。
ライブラリを入れる
パッケージ作成に必要な3つのライブラリを入れます。
pip install hatch ←パッケージ作成用 pip install black ←コードフォーマッタ pip install ruff ←静的解析ツール
blackとruffは必須ではないですが、コードスタイルを強制するために入れとくことにします。詳細はググってください。
以降コマンドプロンプトでhatchを使った作業になります。
プロジェクトを作成する
activateしたコマンドプロンプト上での作業になります。任意の名前のプロジェクトを作ります。
hatch new "プロジェクト名"
これがそのままライブラリの名前になるので慎重に決めましょう。またパッケージのネーミングにも一定のルールがあります。
以下が命名ルールになります。
- すべて小文字
- モジュール名・パッケージ名には “-” を使用しない
- パッケージ名に区切り文字は禁止
- モジュール名(ファイル名)の区切り文字は “_” を使用する(ただこれも非推奨)
cubeという名前でプロジェクトを作ると、
└─cube │ LICENSE.txt │ pyproject.toml │ README.md │ ├─src │ │ │ └─cube │ │ __about__.py │ │ __init__.py │ └─tests __init__.py
こんな感じのディレクトリツリーができます。
pyproject.tomlを編集する
pyproject.tomlの記述をいろいろいじって諸々設定します。ひとまず以下としました。
[build-system] requires = ["hatchling"] build-backend = "hatchling.build" [project] name = "cube" dynamic = ["version"] description = 'equirectangular / cube 360 map' readme = "README.md" requires-python = ">=3.8" license = "MIT" keywords = [] authors = [ { name = "camping engineer", email = "camping.engineer@campkougaku.com" }, ] dependencies = ["opencv-python >= 4.8.0"] [project.urls] Documentation = "https://campkougaku.com" Source = "https://campkougaku.com" [tool.hatch.version] path = "src/cube/__about__.py" [tool.hatch.build] eclude = ["src/cube_test.py", "src/*.tif", "src/*.jpg"] [tool.hatch.envs.lint] detached = true dependencies = [ "black>=23.1.0", "ruff>=0.0.243", ] [tool.hatch.envs.lint.scripts] style = [ "ruff {args:.}", "black --check --diff {args:.}", ] fmt = [ "black {args:.}", "ruff --fix {args:.}", "style", ]
DocumentationとSourceはGitのアドレスがあればそちらを指定するのがよさそうです。
Readmeはマークダウンで記述。今回はPyPIへのアップロードをしないのでそのあたりもごっそり消しました。
__about__.pyにはバージョンを記載します。適当にバージョンを記載します。whlを作り直す場合には必ずインクリメントします。
blackやruffはソースコードをとあるルールに従って整形してくれるので、リリース前には通すことにしておきます。
VSCodeでは保存時に自動実行できるような設定も可能なようです。
ココへ記述する項目の詳細は
とか、
とか。
ソースコードを配置する
src以下、プロジェクト名と同名の__about__.pyがあるフォルダに対してモジュールを配置します。(この例だとcube_map.py)
動作確認用のコードはその上のsrcフォルダに置いておくことにします。(この例だとcube_test.py)このファイルはパッケージには含めないためexcludeします。
└─cube │ LICENSE.txt │ pyproject.toml │ README.md │ ├─src │ │ cube_test.py ←こいつが動作確認用のコード excludeする │ │ │ └─cube │ │ cube_map.py ←こいつが処理モジュール │ │ __about__.py │ │ __init__.py │ └─tests __init__.py
この状態でコーディングとデバッグをすることとします。いらんファイルはexcludeしときます。
eclude = ["src/cube_test.py", "src/*.tif", "src/*.jpg"]
冒頭で作った空っぽの環境スタートなので、必要なライブラリはがつがつ追加していきます。必要なライブラリはpyproject.tomlファイルのdependenciesにも追記します。今回の例ではopencvを依存関係に追加しました。
dependencies = ["opencv-python >= 4.8.0"]
こんな感じ。pip listと打つと今の環境に入っているライブラリの一覧が取れます。必要なものをピックアップします。
__init__.pyを編集する
この__init__.pyですが空っぽでもいいのですが、ライブラリとして仕立てる以上import cubeとして、cube.hoge()で関数アクセスできるようにしたいので、編集します。
あと合わせて、内部で使っているだけの関数は隠蔽して、ライブラリとして公開すべき関数だけ公開します。
from cube.cube_map import equirectangular_to_cube # 公開する関数 from cube.cube_map import cube_to_equirectangular # 公開する関数 __all__ = [ 'equirectangular_to_cube', 'cube_to_equirectangular', ]
こんな感じで、
from ライブラリ名.ファイル名 import 関数名
importした後で__all__にその関数名を追加する。これで使う時には普通のライブラリのごとくimportして公開された関数を使うことができるようになります。
Lintを実行する
blackというライブラリでコードを書き換えてもらって、コードスタイルを強制的にあるルールに従わせます。今回はオプションもとりあえずなしのデフォルトで。
ruffというライブラリを使って静的解析してもらって、怪しいところをアラートしてもらいます。
今回のpyproject.tomlでは
書き換えない(チェックするだけ、後で自分で書き換える)
hatch run lint:style
書き換える(バックアップもなく上書きされる)
hatch run lint:fmt
いろいろ指摘されてしまいます。
buildする
htach build
srcディレクトリと並列にdistディレクトリができ、そこに*.whlと*.tar.gzができます。
このwhlファイルはwheelと呼ばれるファイルで、こいつを使ってpipインストールを行います。
動作確認する
再度まっさらな仮想環境を作ります。コマンドプロンプト上でどこか環境を作る場所へ移動します。
python -m venv testenv /testenv/Script/activate
その環境下で先ほど作ったwhlをインストールします。
pip install xxx.whl
依存関係があるライブラリも同時にインストールされます。これが入った環境でサンプルコードを書いて動けばOK。
コメント