概要
作成したPythonソースコードを他の環境に持って行って実行する、と言う観点でPythonでのパッケージ化の手順を説明する。
ローカルでの配布を想定し、The Python Package Index (PyPI)への登録などは論じない。
作成する配布用ファイルはWheel形式とし、作成方法は「poetry
コマンドを用いる方法」を採用する。
「setup.py
を用いる方法(setup()
を用いる方法)」との対比を意識して説明する。そのため本記事内には、対比先の記事と同一の説明を含む(扱いがsetup()
を用いる場合と同一の個所について)。
目的
Node.jsで言うところの「npm --save install [モジュール名]
コマンドで package.json に構築しておけばOK」をPythonでどうやるのか? という疑問への回答を目的とする。
なお、上記に対してそのまま答えるのであれば「Pythonでは、poetryコマンドで依存関係を管理する場合は、poetry new
で生成されるpyproject.toml
を一緒に添えておけばよい(受け取った側は poetry install
する)」となる。
しかし本記事では、「Pythonでは、パッケージ形式(Wheel形式)に固めて配布し、それをインストールしてパッケージ呼び出し形式で使ってもらう」というケースへの対応を意図する。これは、Pythonの場合はこのケースへの要求が多い、ように感じられたためだ。
想定読者
- はじめてPythonに触れる人で、しかし他の言語でのプログラミング経験は有する方
- Python特有の部分はともかく、とりあえずHello World的な出力は悩まずにPythonでコーディングできる方
- 自身が作成したPythonソースコードで必要な依存関係を、配布時にどう設定すればよいか?に迷っている方
動作環境(検証環境)
次の2つの環境で、サンプルコードの動作確認を実施済み。
- Windows 10
- Python 3.11.5
- WSL2::Ubuntu 22.04.1 LTS
- dockerイメージ「python:3.9-alpine3.18」
なお、「Python仮想環境」(以下、「仮想環境」と略記)を次のように使い分けるので、明示的に記載するようにする(poetryの仮想環境に集約すべきかもしれないが、パッケージ利用環境ではpoetry利用を強制したくない、ので)。
- パッケージの開発場面(動作確認とビルド等)はpoetryの仮想環境を利用
- ビルド済みのパッケージをインストールして動作確認&利用する場面は、Python標準のvenvの仮想環境を利用
※「Python仮想環境とはなんぞや?」と言う方は、付録章の「仮想環境とは?」を参照のこと。
何れの環境でも、poetry
パッケージをpip install poetry
コマンドで、仮想環境にではなく素のPython環境側にインストールしてあるものとする。また、インストール後に以下の設定を実行済みとする(Poetryの仮想環境の作成場所をプロジェクト直下とするオプション設定)。
poetry config virtualenvs.in-project true
サンプルコード
以下を参照のこと。
パッケージ化対象のサンプルコードの仕様
本記事では、動作に追加パッケージを必要とするケースとして、次の仕様のサンプルコードを用いる。
- パッケージの本体は
weaherforecast
フォルダー- フォルダー内のPythonファイル
open_meteo_forecast_api.py
にて、「Open-Meteo」が提供するWeb APIを利用して指定地点の向こう1週間の1h毎の予想気温を取得する関数「get()
」を提供する
- フォルダー内のPythonファイル
- 依存関係としてパッケージ「requests」を必要とする
- 次のようなファイル/フォルダー構造を持つものとする
+-- pyproject.toml
|
\---weatherforecast/
+-- open_meteo_forecast_api.py
+-- __init__.py
+-- __main__.py
上記のコードの動作に必要な依存関係(追加パッケージ)をインストールするには次のようにする1。
poetry shell
poetry add requests
1つ目のコマンドでPoetryの仮想環境に入り、Poetryの依存関係管理を用いて仮想環境にrequstsパッケージをインストールする。
なお、サンプルコードを用いて上記を実行すると、「既に依存関係として追加されている」と言う以下のメッセージが表示される。
The following packages are already present in the pyproject.toml and will be skipped:
• requests
この場合は、続いて以下のコマンド用いる(未追加の場合は、追加のタイミングでインストールも走るので不要)。
poetry install
Poetryの仮想環境に入ったり出たりする方法は、付録章の「仮想環境とは?」を参照のこと。
サンプルコードの動作確認
このサンプルコードの動作確認は、以下のコマンドで実施できる。ここで、上述のpoetry shell
は実行済みであり、Poetryの仮想環境に入っているものとする。
(このコマンドは、サンプルコードのルートから見て、パッケージweatherforecast
を実行している。したがって package直下の__main__.py
が実行される。このフォルダー構造としている理由は、付録章の「ファイル構造に関する補足」を参照のこと)
python -m weatherforecast
上記を実行すると、東京の向こう1週間の1h毎の予想気温が出力される。
パッケージファイル(Wheel形式)の作成方法
pyproject.toml
に必要情報を記載して、poetry build
コマンドを用いて、Wheel形式のパッケージを作成する。本節のコマンドは、素のPython上でもPoetryの仮想環境のどちらで実行しても良い。
pyproject.toml
は例えば、次のように記載する。
[tool.poetry]
name = "weatherforecast"
version = "0.1.0"
description = "sample packages by poetry-toml"
authors = ["Your Name <you@example.com>"]
readme = "README.md"
[tool.poetry.dependencies]
python = ">=3.9,<3.13"
requests = "^2.31.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
このファイルは、ゼロから作成しても良いが、
poetry new [projectname] --name [packagename]
コマンド2を実行すると
次のようなpyproject.toml
ファイルを含んだpoetry標準構成が出力されるので、
こちらの雛型をベースに必要事項を修正、追記するのが楽である3。
[projectname]/
+-- pyproject.toml
+-- README.md
│
├── tests/
│ +-- __init__.py
│
└── [packagename]/
+-- __init__.py
ここで、パッケージの動作に必要な依存関係は、poetry add
コマンドを用いて次のように設定する。
poetry add requests [other-package-name]
すると、poetryがpyproject.toml
の[tool.poetry.dependencies]
セクションに適切に追記してくれる。
なお、poetry new
コマンドを用いて作成したひな形では(環境によるが)次のように初期設定されており、この状態だとpoetry add
コマンドでの任意のパッケージ追加時に「対象のパッケージのPythonバージョン条件(3.11以上、4.00未満)を満たすパッケージが見当たらない」と言うエラーになることがある。
[tool.poetry.dependencies]
python = "^3.11"
その場合は、たとえば次のようにPythonバージョンの条件を狭めるように記載を変更してから、poetry add
コマンドを実行すると良い。
[tool.poetry.dependencies]
python = ">=3.9,<3.13"
もしくは、依存関係として必要なパッケージ一覧を記載したファイルrequirements.txt
がすでに存在している場合は、そちらに基づいてコマンドpoetry add $(cat requirements.txt)
で追加することもできる。
上記のフォルダー構成を作成したら、パッケージフォルダー./[packagename]/
へPythonファイル(Pythonモジュール)を格納する。pyproject.toml
を上述のように作成した後、pyproject.toml
ファイルのあるフォルダーで、おもむろに次のコマンドを実行する。
poetry build
pyproject.toml
ファイルの記述に従い、(name
キーに指定されたフォルダーを対象パッケージとして)パッケージが作成される。
以上で、パッケージ作成は完了。
作成したパッケージの動作確認の方法
Poetryの仮想環境に入っている場合は、いったん仮想環境を抜ける(deactivate
コマンド)。
適当な任意のフォルダーに移動し、そこに真っ新な仮想環境を作成する。
たとえば、次のようにする(ここではPython標準のvenv仮想環境を用いるものとする)。
/home/work/downloads # python -m venv .venv_dl
/home/work/downloads # source .venv_dl/bin/activate
作成したPython仮想環境に入っているパッケージを確認すると、次のようになっている。
(.venv_dl) /home/work/downloads # pip list
---------- -------
pip 23.0.1
setuptools 58.1.0
この環境に対して、先ほど作成したWheelファイル(*.whl
)をpip
コマンドでインストールする。
(.venv_dl) /home/work/downloads # pip install ./dist/weatherforecast-0.0.1-py3-none-any.whl
Processing /home/work/dist/weatherforecast-0.0.1-py3-none-any.whl
Collecting requests<3.0.0,>=2.31.0
Using cached requests-2.31.0-py3-none-any.whl (62 kB)
(略)
インストールが完了後の、状態を確認すると次のようになる。
# pip list
Package Version
------------------ ---------
certifi 2023.7.22
charset-normalizer 3.3.0
idna 3.4
pip 23.0.1
requests 2.31.0
setuptools 58.1.0
urllib3 2.0.6
weatherforecast 0.1.0
インストールしたパッケージを実行するには次のようにする。
python -m weatherforecast
この実行コマンドは「§ サンプルコードの動作確認」で説明したものと同じであり、実行結果も同じとなる。
以上ー。
(付録)
仮想環境とは?
仮想環境とは、「開発環境毎に依存関係を閉じ込める機能」とでも言うべきもの。
たとえばNode.jsであれば「npm install [パッケージA]
を実行すると、そのパッケージはnpm
コマンドを実行したフォルダー配下でのみ有効」であり、別のフォルダーでnpm instal [パッケージ@バージョン]
コマンドを実行した場合はそれぞれのフォルダー毎に異なるバージョンのパッケージを利用する事が可能(「ローカルにインストールする」と呼称する。すべてのフォルダーで利用可能にするには「npm instal [パッケージ名] -g
」コマンドで明示的に「グローバルにインストールする」必要がある)。しかしPythonでは「ローカルにインストールする」と言う概念はない。代わりに「仮想環境」を作成して入った状態では、pip install [パッケージ名]
でインストールしたパッケージは、その「仮想環境」の中でのみ利用可能となる。異なる仮想環境を作ることで、異なるバージョンのパッケージをインストールして利用することが可能となる。
具体的な仮想環境の作成と、その中に入る2種類の手順を次に示す。
Python標準のvenvパッケージ利用の場合
(1つ目のコマンドの2つ目の引数は任意の識別子だが説明は省略)
python -m venv .venv
.venv\Scripts\activate
# ↑Windowsの場合。↓Linuxの場合は↓。
# source .venv/bin/activate
以降のpip install
コマンド、Python
コマンドはいずれも、この「仮想環境」での動作となる。「仮想環境」を一度作成したら、以降はsource .venv\bin\activate
コマンドのみで良い。
なお、仮想環境の実態は「python -m venv .venv
」を実行したフォルダ配下に作成されるフォルダ「.venv
」となる。2回目以降に「仮想環境」に入るには、そのフォルダ「.venv
」があるところで実行する。
「仮想環境」を抜けるには次のコマンド用いる(※別の「仮想環境」に入るには、いったん抜けること)。
deactivate
Poetryパッケージ利用の場合
Poetryに対して以下のコマンドを実行済み(Poetryの仮想環境の作成場所をプロジェクト直下とするオプション値)。
poetry config virtualenvs.in-project true
新規に仮想環境を作成するには、次のコマンドを実行する。実行と同時に仮想環境中に入った状態となる。
poetry shell
以降のPython
コマンドは、この「仮想環境」での動作となる。なお、パッケージの追加インストールにはpoetry add [パッケージ名]
を用いる。これによりpyproject.toml
ファイルにも自動で依存関係が記録される。
「仮想環境」を抜けるには次のコマンド用いる(※別の「仮想環境」に入るには、いったん抜けること)。
deactivate
作成済みの「仮想環境」に、一度抜けた後に改めて入るには次のコマンドを用いる。
source .venv\bin\activate
仮想環境の実態は「poetry shell
」を実行したフォルダ配下に作成されるフォルダ「.venv
」となる。2回目以降に「仮想環境」に入るには、そのフォルダ「.venv
」があるところで実行する。
なお、2回目以降の仮想環境への入り方は、より正確には次のコマンドとなる。ここでpoetry env info --path
が返す値は、上述の.venv
への絶対パスである。なので、フォルダ「.venv
」があるところで実行する分には、上記のように直接指定で良い。
`source $(poetry env info --path)/bin/activate`
Poetry仮想環境に関する参考サイト
- 基本的な使い方 - Poetry documentation (ver. 1.1.6 日本語訳)
新しいシェルの作成を避けるには、source {path_to_venv}/bin/activate (Windowsでは source {path_to_venv}\Scripts\activate.bat) コマンドを実行して、手動で仮想環境を起動する方法があります。仮想環境のパスを取得するには、 poetry env info --path コマンドを実行します。
- Poetry実践入門 #自分用メモ
- 【Poetry使い方から仮想環境の削除まで】Pythonパッケージ管理の完全ガイド
ファイル構造に関する補足
- Pythonにおいて、「パッケージ」とは「モジュールをまとめて格納したフォルダー」のことを意味する。「モジュール」とは「Pythonファイル(*.py)」を意味する
- 「パッケージ化する」とは「パッケージ(フォルダー)に格納したモジュール一式を、配布形式にする」と言える
- したがって上記のように「対象の関数を定義したPythonソースコードを、フォルダー配下に格納した状態」とするのが望ましいようだ
-
Poetry関係しない動作確認だけが目的の場合は
pip install requests
でも良いのだが、今回はpoetryでの動作確認が目的なので、このようにする。 ↩ -
「このコマンドは、ほとんどのプロジェクトに適するディレクトリ構造を作成して、新しいPythonプロジェクトに勢いをつける助けをしてくれます」, https://cocoatomo.github.io/poetry-ja/cli/#new ↩
-
既存のPythonソースコードに対してパッケージの設定を行う際には、
poetry init
コマンドを用いる方法もある。 , https://cocoatomo.github.io/poetry-ja/cli/#init ↩