他のプログラミング言語の経験がある方がPythonへ入門する際に、「Pythonでコードを配布する方法は?」「『パッケージ』という言葉が指すものはNode.jsと同じなの?」などのプログラミング言語間の扱いの違いに戸惑いを覚えたことはないでしょうか?
本書は、作成したPythonのコードを「他の環境に持って行って実行する」という観点で、依存関係を含めて容易に他環境へインストールするための配布用ファイル形式の作り方、を解説します。Node.jsであれば、次のような作業を行う場面でPythonならどうするか?という話となります。
1.ルートにindex.jsを作成し、パッケージとして公開したい関数orクラスをexportする
2.npmコマンドでパッケージを作成する
3.npmコマンドでパッケージをインストールして、提供された関数orクラスの機能を利用する
今しがた用いてきた『パッケージ』という言葉もそうですが、用語のいくつかはプログラミング言語によって定義(指す対象)が一般に異なります。また、歴史的経緯により、現状のPythonでは配布用ファイルの作り方が複数用いられています。これらを踏まえて「他のプログラミング言語の経験はあるが、Python言語は初めて」という方向けに、配布用ファイル形式の作り方を3種類と、その際の理解に必要なPythonでの用語の定義を解説します。
本書は次のことを目的とします。
・作成したPythonコードをまとめて、pipコマンドで依存関係も含めてインストールできる配布用ファイル形式として作成できること
・作成したファイルをインターネット越しに配布する方法の種類を理解し、そして実際に配布できること
本書の想定する読者は次の方です。
・他の言語でのプログラミング経験はあるが(たとえばNode.jsなど)、Python言語にはあまり馴染みがない方
・作成したPythonのコードを開発環境とは異なる環境へ提供して(配布して)、動作させたい方
・配布パッケージファイル(Wheelファイル)は存じており、作成方法もひとつは知っているが他の方法も知りたい方
本書で解説するのは次の内容です。
・配布用のファイル作成の手順の理解に必要な用語と操作の概念
・配布用のファイル形式の作成に必要な各ファイル作成のPython言語における立ち位置と、依存関係の設定を含めた具体的な作成手順
─Pyarmorを用いてコードの難読化してから含める方法も付録で解説します
─GitHub Actionsを用いて作成を自動化する方法も付録で解説します
・作成した配布用のファイルをインストールした環境での、提供した関数の動作確認手順
─ファイルをコピーするなどして提供先のローカルに配置して、そこからのインストールする想定です
・作成した配布用のファイルをネットワーク経由で配布する方法
─PyPI(npm等に相当)とGitHubのリポジトリを用いる方法を、付録にてそれぞれ簡単に解説します
本書で解説しないことは次の内容です。
・Python言語によるプログラミング方法そのもの
・依存関係を管理する方法や配布手段におけるベストプラクティス
・PyPIにおける配布の仕組みそのもの
・GitHubリポジトリ、GitHub Actions自体の使い方
なお本書で解説する内容は、Pythonの解説書籍やPython公式を含むWebサイトを参照することで取得可能です。しかし、Python初心者がそれらの情報にたどりつくのは「検索方法がわからない」、「複数を渡り歩く必要がある」ことから容易ではなく労力がかかると考えます。本書は、それらの手間暇を軽減することを目的とします。
本書でのサンプルの記載は、多くの場合はキーとなるコード部分の抜粋となります。サンプルコードの全体は次のサポートページにて公開しています。実際に動作確認を行う際には、そちらのソースコードを利用してください。
・Windows 10
─Python 3.11.5
・Ubuntu 22.04(Docker on WSL2内)
─Python 3.9 (python:3.9-alpine3.18)
本章中のスクリーンショットや利用ライブラリのバージョンは、2023/10/31現在のものです。その後に変更されている場合があります。
本書に記載された内容は、情報の提供のみを目的としています。したがって、本書を用いた開発、製作、運用は、必ずご自身の責任と判断によって行ってください。これらの情報による開発、製作、運用の結果について、著者はいかなる責任も負いません。
本書に記載されている会社名、製品名などは、一般に各社の登録商標または商標、商品名です。会社名、製品名については、本文中では©、®、™マークなどは表示していません。
本章では、Pythonのパッケージ周りに初めて触れる前提で、Pythonの配布用ファイル作成の理解に必要な用語と概念を解説します。
Pythonの言語仕様や推奨される規則、その仕様に至った歴史、論理的根拠などを記録した設計文書のことを「PEP」と呼称します1。PEPはPython Enhancement Proposalの略です。Pythonの実装は「PEP xxxに準拠した実装」などのように行われています。簡単に言えば「PEPは、Pythonインタプリタが従うべき仕様書」となります。Pythonインタプリタの仕様のみでなく、Python言語として推奨コーディング規約などもPEPで定められています2。
Pythonで作成したコード一式を配布する際は、パッケージングを行い配布パッケージの形にまとめます(この後で改めて説明します)。このようなPythonでのパッケージと配布のエコシステムの標準仕様を策定、管理しているワーキングループを「PyPA」と呼称します。PyPAはPython Packaging Authorityの略です3。
Pythonで書かれた単一の*.pyファイルを「モジュール(Module)」と呼称します4。より正確には、「Pythonにおけるコードの再利用性の基本単位」として定義され、「Pure Module」5と「Extension Module」6の2種類に分かれますが、本書では以降「Pure Module」のことを指して「モジュール」と呼称します7。
複数の「モジュール」を集約したディレクトリのことを「パッケージ」と呼称し、「パッケージ」を配布用に整えたものを「配布パッケージ」(もしくは「配布用のパッケージ」)と呼称します8。
以降、本書ではモジュール、パッケージ、配布パッケージ、と括弧書きを付けずに記載します。
配布パッケージを取得してインストールする際には、Python標準に含まれているpipコマンド9が一般に利用されます。pipは「パッケージ管理システム」のひとつです。特に指定がない場合は、pipコマンドはWheelファイル形式10の配布パッケージを選好します11。Wheelファイル形式の配布パッケージを用いると、利用者は特別なコンポーネントの構築ツールや経験を必要とせずに対象のパッケージを自身の環境で利用できます。Pythonで用いられる配布パッケージの形式はいくつか存在しますが、本書では以降で特に断らない場合は、PyPAが推奨するWheelファイル形式を指すものとします12。
本書では、Wheelファイルのフォーマット13自体には踏み込みません。Wheelファイルを作成するためのツールの実行方法と、作成されたWheelファイルをローカルで利用する方法14、の観点で解説します。Wheelファイルをインターネットを通じて配布する方法に興味のある方は、付録E「Python配布パッケージをGitHubリポジトリで配布する方法」と付録F「Python配布パッケージをPyPIリポジトリで配布する方法」で簡単に触れていますので、参照ください。
Pythonに標準で含まれているパッケージ以外の、任意のサードパーティー製のパッケージが提供する機能を利用する場面を考えます。機能の例としては、インターネットアクセスを容易にするパッケージである「requests」や、データ処理を(データのクレンジングを)容易にするパッケージである「pandas」、などを用いる場面です。
これらの機能は、配布パッケージの形式でPyPIにて公開されているので、pipコマンドを用いて自身の利用環境へ簡単に追加できます(パッケージをインストールできます)。pipコマンドを単純に実行すると、対象パッケージはグローバル環境にインストールされます。そうすると、アプリケーションAではパッケージZのVersion 1.0を必要とするが、一方でアプリケーションBではパッケージZのVersion 2.0を必要とする、という場面で困ったことになります。これを解決するために、Pythonでは「Python仮想環境」という概念を利用します(以降、「仮想環境」と略す。とくに断らない限りPythonの仮想環境を指す)。標準に含まれない追加のパッケージをインストールする際には、必須ではありませんが仮想環境を構築してからインストールすることが推奨されます15。
仮想環境を作成して、「その環境の中で」pipによるパッケージのインストールとアプリケーションを実行することで「アプリケーション固有の隔離された環境で実行」できます。仮想環境はそれ自身のインストールディレクトリを持ち、他の仮想環境とライブラリを共有しません。これにより、グローバル環境を汚さずにアプリケーションの動作に必要なパッケージの依存関係をアプリケーション単位でインストールできます。
現在、次のふたつのPython仮想環境を構築するためのツール(パッケージとして提供)がよく知られています。
・venv
・virtualenv
venvパッケージはvirtualenvのパッケージのサブセットであり、Pythonに標準で含まれているパッケージであり、pipコマンドによる追加インストールなしに利用できます。
本書では、利用の簡単なvenvパッケージ(venvコマンド)を用いるものとします。仮想環境の具体的な利用方法は「2.3.1 仮想環境venvの作成」と「2.4.2 仮想環境poetry shellを作成」16で解説します。
配布することを考慮したパッケージを作成する際に、推奨されるフォルダー構成はリスト1.1の通りです。一般にこのような一式をプロジェクトと呼称し、ひとつのプロジェクトではひとつのパッケージを含めます。
project_root
+--[パッケージのメタ情報を記述したファイル].xxx
+--・・・(ビルド方法や依存関係のパッケージなど)・・・
|
+--[パッケージ名]/
| +--[パッケージを構成するモジュール].py
| +--・・・
| |
| +--__init__.py
| +--__main__.py
|
+--[パッケージのテストコードなど]
\--・・・
リスト1.1は抽象度が高すぎるため、ある程度まで想定場面を絞ったサンプルを用いて、以降では推奨フォルダー構成を解説します。なお、配布パッケージの作成に用いるツールにより若干の差分があるため、実際に動作可能なファイル・フォルダー構成の具体例は、配布パッケージ作成の方式別に解説している第2章を参照ください。
サンプルとして、「向こう1週間の天気の予想気温を取得する」機能を提供するパッケージ「weatherforecast」を作成する場面を考えます。このパッケージは、次のモジュールをまとめたもの(集約したもの)とします。ファイル名などは本節での限定的なものとします(第2章で用いるサンプルコードより抽象度が高いです)。
・天気の予想気温を取得するモジュール「forecast.py」
・取得した予想気温をインプットとして特性を出力するモジュール「analyse.py」
これらのモジュールを集約したパッケージを作成する際に推奨されるファイル・フォルダー構成例はリスト1.2です17。これは最低限の要素での構成例です。
project_root
+--setup.py or pyproject.toml
+--README.md
+--LICENSE.txt
|
\--weatherforecast/
+--forecast.py
+--analyse.py
+--__init__.py
リスト1.2の構成要素は表1.1の通りです。
ファイル・フォルダー名 | 目的 |
setup.py or pyproject.toml | 配布パッケージ化する際の作業項目を記載したファイル18。 |
README.md | パッケージに関する説明を記載したファイル |
LICENSE.txt | 配布の条件を指定するライセンスファイル(※外部に公開する場合) |
weatherforecast/ | パッケージ本体であるフォルダー |
forecast.py, analyse.py | 含めるパッケージに集約したモジュール |
__init__.py | パッケージとするフォルダーに一般に含めるファイル |
リスト1.1において、次のファイル群は「パッケージのメタ情報を記述したファイル」に該当し、記載の通りの固定のファイル名での構成が推奨されます(変更できないわけではありません)。
・setup.py
・pyproject.toml
・README.md
・LICENSE.txt
上記の他に、必要に応じて「requirements.txt」や「MANIFEST.in」ファイル、また「docs/」フォルダーなどを追加する場合もありますが、説明は割愛します。
リスト1.1においてフォルダーは「パッケージ名」に該当します。
・weatherforecast/
このフォルダー名は任意です。PEP8に記載されている命名規約に沿って、パッケージの目的が分かりやすい名称を付けます19。このフォルダー配下に、パッケージにまとめるモジュール一式を格納します(__init__.py以外のモジュール名も任意です)。
これらの他に、必要に応じて表1.2のようなフォルダー等を含める場合もありますが、説明は割愛します。
フォルダー名 | 目的 |
venv/ | 仮想環境の格納先(venvコマンドにより自動生成) |
tests/ | UnitTestコードの格納先 |
docker/ | Dockerプロジェクトの格納先 |
notebooks/ | Jupyter Notebookファイルの保管先 |
examples/ | 使用例(サンプルコードなど)の格納先 |
本書は、PyPAの提供する「Python Packaging User Guide」での記載に準じて推奨フォルダー構成を解説しています。その際に、「ゼロから学ぶPython」と「The Hitchhiker's Guide to Python」も併せて参照し、次の方針で修正した(主に簡素化)ファイル・フォルダー構成としてします。
・setup.cfgは、setup.pyの観点からは設定の外部ファイル化なので、説明を簡単にする目的で省略(setup.py側にマージしたケースとした)
・MANIFEST.inは、通常の配布パッケージに含める種類のファイルのみの構成であれば不要となるので、省略
・「ガイド型文書 > パッケージングとプロジェクトの配布」ではsetup.pyでの案内だが、「チュートリアル型文章>Pythonのプロジェクトをパッケージングする」では代わりにpyproject.tomlでの案内のため、両方式を併記
その上で、本書では仮想環境にvenvパッケージを用いていることを考慮しての補足、「Pytest」での「test layout: Tests outside application code」を参照しての補足を加えています。
主な参照先のリストは以下です。
・PyPA > Python Packaging User Guide > ガイド型文書 > パッケージングとプロジェクトの配布
─https://packaging.python.org/ja/latest/guides/distributing-packages-using-setuptools/
・ゼロから学ぶPython > 4. モジュールとパッケージ > 4.7. プロジェクト構成
─https://rinatz.github.io/python-book/ch04-07-project-structures/
・The Hitchhiker's Guide to Python > プロジェクトの構造化
─https://python-guideja.readthedocs.io/ja/latest/writing/structure.html
・pytest > Good Integration Practices > Choosing a test layout / import rules