自分で書いたコードを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。
コメント