はじめに
Python パッケージは、コードを整理し配布するための強力な手段です。Python スクリプト (.py ファイル) がパッケージの中核を成しますが、設定ファイル、データファイル、テンプレート、ドキュメントなど、追加のファイルを含める必要が頻繁にあります。このチュートリアルでは、これらの追加リソースを含む Python パッケージを作成するプロセスを案内し、パッケージをより多用途で有用なものにします。
この実験(Lab)の終わりには、追加ファイルを含む完全な Python パッケージを作成し、コードからこれらのファイルにアクセスする方法を習得します。
基本的な Python パッケージ構造の作成
基本的な Python パッケージ構造を作成することから始めましょう。パッケージは、本質的に Python モジュールと、このディレクトリをパッケージとして扱うように Python に指示する特別な __init__.py ファイルを含むディレクトリです。
パッケージディレクトリ構造の作成
まず、パッケージに必要なディレクトリを作成しましょう。
mkdir -p ~/project/mypackage/data
このコマンドは、追加ファイルを保存するためのサブディレクトリ data を持つ mypackage というディレクトリを作成します。
次に、プロジェクトディレクトリに移動しましょう。
cd ~/project
基本的なパッケージファイルの作成
すべての Python パッケージには、ルートディレクトリに __init__.py ファイルが必要です。このファイルを作成しましょう。
touch mypackage/__init__.py
この空のファイルは、mypackage ディレクトリがパッケージであることを Python に伝えます。
次に、パッケージ内にシンプルな Python モジュールを作成しましょう。
echo 'def greet():
print("Hello from mypackage!")' > mypackage/greeting.py
パッケージへのデータファイルの追加
次に、パッケージにデータファイルを追加しましょう。これは、設定ファイル、CSV ファイル、またはパッケージが必要とするその他のタイプのファイルです。
echo 'This is sample data for our package.' > mypackage/data/sample.txt
設定ファイルも作成しましょう。
echo '[config]
debug = true
log_level = INFO' > mypackage/config.ini
パッケージ構造の検証
次のコマンドでパッケージの構造を確認できます。
find mypackage -type f | sort
次のような出力が表示されるはずです。
mypackage/__init__.py
mypackage/config.ini
mypackage/data/sample.txt
mypackage/greeting.py
これは、いくつかの追加の非 Python ファイルを含む基本的な Python パッケージ構造です。次のステップでは、パッケージを配布する際にこれらのファイルを含める方法と、コードからそれらにアクセスする方法を学びます。
パッケージのセットアップスクリプトの作成
Python パッケージに追加のファイルを適切に含めるには、setup.py ファイルを作成する必要があります。このファイルは、Python のパッケージングツールによってパッケージをビルドおよびインストールするために使用されます。
setup.py の理解
setup.py ファイルには、パッケージの名前、バージョン、作成者、依存関係など、パッケージに関するメタデータが含まれています。また、パッケージを配布する際に含めるファイルも指定します。
プロジェクトのルートディレクトリに基本的な setup.py ファイルを作成しましょう。
cd ~/project
次に、次の内容で setup.py ファイルを作成します。
cat > setup.py << 'EOF'
from setuptools import setup, find_packages
setup(
name="mypackage",
version="0.1",
packages=find_packages(),
## Include data files
package_data={
"mypackage": ["config.ini", "data/*.txt"],
},
## Metadata
author="Your Name",
author_email="your.email@example.com",
description="A simple Python package with additional files",
)
EOF
パッケージデータ設定の理解
package_data パラメータは、パッケージに追加のファイルを含めるための鍵となります。これは、次のような辞書を受け取ります。
- キーはパッケージ名(またはすべてのパッケージの場合は "")
- 値はパッケージディレクトリからの相対的なファイルパターンのリスト
この例では、以下を含めています。
- パッケージのルートにある
config.iniファイル dataディレクトリ内のすべての.txtファイル
ファイルパターンは、類似の名前または拡張子を持つ複数のファイルに一致させるために、* などのワイルドカードをサポートしています。
セットアップ設定のテスト
パッケージをテストするために、仮想環境を作成しましょう。
python3 -m venv ~/project/venv
source ~/project/venv/bin/activate
次に、開発モードでパッケージをインストールしましょう。
cd ~/project
pip install -e .
-e フラグは「編集可能(editable)」モードを表し、パッケージコードを編集しても、毎回再インストールする必要がないことを意味します。
パッケージが正常にインストールされたことを示す出力が表示されるはずです。
Successfully installed mypackage-0.1
パッケージのインストールを確認しましょう。
python -c "import mypackage.greeting; mypackage.greeting.greet()"
これは次のように出力されるはずです。
Hello from mypackage!
これで、追加ファイルを含むセットアップスクリプトを使用して、Python パッケージを正常に作成できました。次のステップでは、Python コードからこれらのファイルにアクセスする方法を学びます。
パッケージ内の追加ファイルへのアクセス
パッケージに追加のファイルを含めたので、Python コードからそれらにアクセスする方法を学ぶ必要があります。これを行う方法はいくつかありますが、最も信頼できる方法は、setuptools パッケージの pkg_resources モジュールを使用することです。
追加ファイルにアクセスするためのモジュールの作成
追加ファイルにアクセスする方法を示す新しいモジュールをパッケージに作成しましょう。
cd ~/project
mypackage ディレクトリに fileaccess.py という名前の新しいファイルを作成します。
cat > mypackage/fileaccess.py << 'EOF'
import os
import pkg_resources
def get_config_path():
"""Return the path to the config.ini file."""
return pkg_resources.resource_filename('mypackage', 'config.ini')
def read_config():
"""Read and return the content of the config.ini file."""
config_path = get_config_path()
with open(config_path, 'r') as f:
return f.read()
def get_sample_data_path():
"""Return the path to the sample.txt file."""
return pkg_resources.resource_filename('mypackage', 'data/sample.txt')
def read_sample_data():
"""Read and return the content of the sample.txt file."""
data_path = get_sample_data_path()
with open(data_path, 'r') as f:
return f.read()
def list_package_data():
"""List all files included in the package data."""
## Get the package directory
package_dir = os.path.dirname(pkg_resources.resource_filename('mypackage', '__init__.py'))
## List files in the main package directory
main_files = [f for f in os.listdir(package_dir)
if os.path.isfile(os.path.join(package_dir, f))]
## List files in the data directory
data_dir = os.path.join(package_dir, 'data')
data_files = [f'data/{f}' for f in os.listdir(data_dir)
if os.path.isfile(os.path.join(data_dir, f))]
return main_files + data_files
EOF
__init__.py ファイルの更新
新しい関数を公開するために、__init__.py ファイルを更新しましょう。
cat > mypackage/__init__.py << 'EOF'
from mypackage.greeting import greet
from mypackage.fileaccess import (
get_config_path,
read_config,
get_sample_data_path,
read_sample_data,
list_package_data
)
__all__ = [
'greet',
'get_config_path',
'read_config',
'get_sample_data_path',
'read_sample_data',
'list_package_data'
]
EOF
ファイルアクセス関数のテスト
ファイルアクセス関数をテストするスクリプトを作成しましょう。
cat > ~/project/test_package.py << 'EOF'
import mypackage
## Test greeting function
print("Testing greeting function:")
mypackage.greet()
print()
## Test config file access
print("Config file path:")
print(mypackage.get_config_path())
print("\nConfig file content:")
print(mypackage.read_config())
print()
## Test data file access
print("Sample data file path:")
print(mypackage.get_sample_data_path())
print("\nSample data file content:")
print(mypackage.read_sample_data())
print()
## List all package data
print("All package data files:")
for file in mypackage.list_package_data():
print(f"- {file}")
EOF
次に、テストスクリプトを実行します。
cd ~/project
python test_package.py
次のような出力が表示されるはずです。
Testing greeting function:
Hello from mypackage!
Config file path:
/home/labex/project/mypackage/config.ini
Config file content:
[config]
debug = true
log_level = INFO
Sample data file path:
/home/labex/project/mypackage/data/sample.txt
Sample data file content:
This is sample data for our package.
All package data files:
- __init__.py
- config.ini
- fileaccess.py
- greeting.py
- data/sample.txt
pkg_resources の理解
pkg_resources モジュールは、インストールされたパッケージ内のリソースにアクセスする方法を提供します。resource_filename 関数は、パッケージがインストールされている場所に関係なく、パッケージ内のファイルへのパスを返します。
このアプローチにより、次のいずれの場合でも、コードが追加ファイルにアクセスできるようになります。
- 開発中にソースディレクトリから実行している場合
- 仮想環境にインストールされている場合
- システム全体にインストールされている場合
- 別のマシンに配布およびインストールされている場合
これにより、パッケージはよりポータブルで信頼性が高くなります。これは、パッケージの使用方法に応じて変化する可能性のあるハードコードされたパスや相対パスに依存しないためです。
パッケージのビルドと配布
追加ファイルを含む Python パッケージを作成し、それらにアクセスできることを確認したので、このパッケージをビルドして配布する方法を学びましょう。
セットアップスクリプトの更新
パッケージをビルドする前に、より多くのメタデータと要件を含めるように setup.py ファイルを更新しましょう。
cd ~/project
cat > setup.py << 'EOF'
from setuptools import setup, find_packages
setup(
name="mypackage",
version="0.1.0",
packages=find_packages(),
## Include data files
package_data={
"mypackage": ["config.ini", "data/*.txt"],
},
## Dependencies
install_requires=[
"setuptools",
],
## Metadata
author="Your Name",
author_email="your.email@example.com",
description="A simple Python package with additional files",
keywords="sample, package, data",
url="https://example.com/mypackage",
classifiers=[
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
],
python_requires=">=3.6",
)
EOF
ソースおよび Wheel ディストリビューションのビルド
Python パッケージはいくつかの形式で配布できますが、最も一般的なのは次のとおりです。
- ソースディストリビューション (sdist): ソースコードと追加ファイルを含む tarball
- Wheel ディストリビューション (bdist_wheel): ビルドせずにインストールできる、事前にビルドされたパッケージ
両方のタイプのディストリビューションを作成しましょう。
## Make sure we have the latest build tools
pip install --upgrade setuptools wheel
## Build the distributions
python setup.py sdist bdist_wheel
ディストリビューションが作成されたことを示す出力が表示され、新しいファイルが dist ディレクトリに表示されるはずです。
dist ディレクトリの内容を確認しましょう。
ls -l dist
少なくとも 2 つのファイルが表示されるはずです。
.tar.gzファイル (ソースディストリビューション).whlファイル (wheel ディストリビューション)
ディストリビューションファイルからのパッケージのインストール
次に、ディストリビューションファイルの 1 つからパッケージをインストールするテストを行いましょう。まず、開発バージョンをアンインストールしましょう。
pip uninstall -y mypackage
次に、wheel ディストリビューションをインストールしましょう。
pip install dist/mypackage-0.1.0-py3-none-any.whl
パッケージが正常にインストールされたことを示す出力が表示されるはずです。
パッケージがインストールされ、追加ファイルに引き続きアクセスできることを確認しましょう。
python -c "import mypackage; print(mypackage.read_config())"
これにより、config.ini ファイルの内容が出力されます。
[config]
debug = true
log_level = INFO
パッケージの公開
実際のシナリオでは、通常、Python Package Index (PyPI) にパッケージを公開して、他の人が pip install mypackage を使用してインストールできるようにします。これには、以下が含まれます。
- PyPI でアカウントを作成する (https://pypi.org/)
twineなどのツールを使用してディストリビューションをアップロードする:pip install twine twine upload dist/*
ただし、この実験では、ローカルでディストリビューションを作成する段階で終了します。これで、他の人が配布およびインストールできる追加ファイルを含む完全な Python パッケージが完成しました。
作成したものの概要
- モジュールと追加ファイルを含む Python パッケージ
- ディストリビューションにこれらのファイルを含めるセットアップスクリプト
- コードからこれらのファイルにアクセスするための関数
- 配布の準備ができたソースおよび wheel ディストリビューションファイル
この構造は、将来作成する可能性のあるすべての Python パッケージの強固な基盤を提供します。
まとめ
この実験では、以下の方法を学びました。
- Python 以外の追加ファイルを含む基本的な Python パッケージ構造を作成する
- パッケージ配布にこれらのファイルを含めるように
setup.pyを設定する pkg_resourcesモジュールを使用して、Python コードから追加ファイルにアクセスする- 配布用にパッケージのソースおよび wheel ディストリビューションをビルドする
これで、Python コードだけでなく、設定ファイル、データファイル、テンプレート、その他のリソースも含む、より包括的な Python パッケージを作成するための知識が得られました。この機能は、Python コードが外部ファイルと連携する必要がある実際のアプリケーションを開発するために不可欠です。
この実験からの主なポイントは次のとおりです。
setup()でpackage_dataパラメータを使用して追加ファイルを含めるpkg_resources.resource_filename()を使用して、コードからこれらのファイルに確実にアクセスする- 最大限の互換性のために、ソースと wheel の両方のディストリビューションをビルドする
- メンテナンスを容易にするために、パッケージ構造を整理する
この知識は、より複雑な Python アプリケーションとパッケージを開発し続ける際に役立ちます。



