極簡Pythonパッケージガイド


本文は
qbit『pytestテスト実戦・付録Dパッケージ&リリースPythonプロジェクト』・Brian Okken著・華中科技大学出版社より整理
qbitの実験環境
Windows 10 x64
Python  3.6.7 x64

プロジェクトのパッケージとパブリケーションは重要です.ほとんどのPython開発者はこの分野に詳しくありませんが、実際にはこの問題を真剣に見る必要があります.結局、共有コードもPython開発の仕事の一部です.そのため、Python内蔵のツールを合理的に使って共有コードを開くことが重要です.これは大きな話題ですが、紙面の制限で全面的に紹介できません.ここでは、従来の共有コードの方法についてのみ説明します.これらの方法をマスターしたら、少なくとも圧縮されたファイルやモジュールを電子メールで送信する必要はありません.pipでインストールできるようにプロジェクトを設定する方法を紹介します.プロジェクトをソースコード形式でパブリッシュする方法.プロジェクトをwheelファイルにパッケージする方法.これらのテクニックは、スモールチーム内でコードを共有するのに十分です.PyPIでコードをインターネットに共有したい場合は、お勧めのドキュメントをお読みください.今から始めましょう.
インストール可能なモジュールの作成
Creating an Installable Module
まず、小さなプロジェクトをpipにインストールする方法を学びます.単一モジュールのみのプロジェクトを例に挙げます.実際のプロジェクトは通常こんなに簡単ではありません.私はこの例を選んだのは、メンテナンス可能なプロジェクトを作成する方法とsetupを示すためだけです.pyファイルはどんなに簡単ですか.簡単なディレクトリ構造を次に示します.
some_module_proj
  |--setup.py
  |--some_module.py

共有したいコードはsome_molule.pyファイル:
# D:\Python3Project\test\some_module_proj\some_module.py
def some_func():
    return 42

pipにインストールできるようにsetupが必要です.pyファイル.以下は最も簡潔なsetupです.pyコード:
# D:\Python3Project\test\some_module_proj\setup.py
from setuptools import setup
setup(
    name='some_module',
    py_modules=['some_module']
)

1つのディレクトリ、1つのモジュール、1つのsetup.pyファイルは、プロジェクトをpipにインストールするのに十分です.
D:\Python3Project\test
λ pip3 install .\some_module_proj\
Processing d:\python3project\test\some_module_proj
Installing collected packages: some-module
    Running setup.py install for some-module ... done
Successfully installed some-module-0.0.0

Pythonプログラムでsome_を使用できるようになりましたmoluleです.
D:\Python3Project>python
Python 3.6.7 (v3.6.7:6ec5cf24b7, Oct 20 2018, 13:35:33) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from some_module import some_func
>>> some_func()
42
>>> exit()

これは理想化された状況である.実際の作業では、プロジェクトをパッケージ化することが一般的です.次のセクションではsetupを変更する方法について説明します.pyファイルを使用してプロジェクトのパッケージを完了します.
インストール可能なパッケージの作成
Creating an Installable Package
パッケージ名のディレクトリを作成してからinit__.pyファイルは関連モジュールとともにこのディレクトリに格納されます.
some_package_proj
 |--setup.py
 |--src
     |--some_package
         |--__init__.py
         |--some_module.py

some_module.pyファイルの内容は変わりません.init__.pyファイルは、モジュールの機能をパッケージネーミングスペースを介して外部に露出する必要があります.いろいろな方法がありますが、Pythonドキュメントのこのトピックに関する2つのセクションを参照してください(https://docs.python.org/3/tutorial/modules.html#packages).にある場合init__.pyファイルには次のように書かれています.
import some_package.some_module

呼び出し側のコードはsome_を示す必要がありますmodule.
import some_package
some_package.some_module.some_func()

でもsome_module.pyはAPI機能の一部であり,パケットという階層の情報を提供すべきである.だから、私たちはこのように書くべきです.
# D:\Python3Project\test\some_package_proj\src\some_package\__init__.py
from some_package.some_module import *
# or 
from .some_module import *

呼び出し側コードは次のように書くことができます.
import some_package
some_package.some_func()

setupも必要です.pyファイルを少し変更します.
# D:\Python3Project\test\some_package_proj\setup.py
from setuptools import setup, find_packages
setup(
    name='some_package',
    packages=find_packages(where='src'),
    package_dir={'': 'src'},
)

後で呼び出すにはpy_は必要ありませんmodulesです.パッケージを指定するだけです.インストールできるようになりました.
D:\Python3Project\test
λ pip3 install .\some_package_proj
Processing d:\python3project\test\some_package_proj
Installing collected packages: some-package
    Running setup.py install for some-package ... done
Successfully installed some-package-0.0.0

しかもそのまま使えます.
D:\Python3Project\test\some_package_proj\src>python
Python 3.6.7 (v3.6.7:6ec5cf24b7, Oct 20 2018, 13:35:33) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from some_package import some_func
>>> some_func()
42

プロジェクトはインストールでき、モジュール呼び出しが容易です.srcと同じクラスのディレクトリにtestsディレクトリを追加し、テスト例を入れることができます.だが...pyファイルには重要な内容が欠けており、ソースコードを正常にパブリッシュしたり、wheelファイルを作成したりすることはできません.しかし、私たちは少し修正すればいいだけです.
ソースパブリッシュパッケージとWheelファイルの作成
Creating a Source Distribution and Wheel
個人的に使用する場合は、前節で説明した方法でソースパブリッシュパッケージとwheelファイルを作成するのに十分です.次はやってみます.
  • パッケージwheelフォーマットはwheelパッケージ
  • をインストールする必要があります.
    pip3 install wheel
    λ python3 setup.py sdist bdist_wheel
    running sdist
    running egg_info
    creating src\some_package.egg-info
    writing src\some_package.egg-info\PKG-INFO
    writing dependency_links to src\some_package.egg-info\dependency_links.txt
    writing top-level names to src\some_package.egg-info\top_level.txt
    writing manifest file 'src\some_package.egg-info\SOURCES.txt'
    reading manifest file 'src\some_package.egg-info\SOURCES.txt'
    writing manifest file 'src\some_package.egg-info\SOURCES.txt'
    warning: sdist: standard file not found: should have one of README, README.rst, README.txt, README.md
    ......
    D:\Python3Project\test\some_package_proj
    λ dir /B dist
    some_package-0.0.0-py3-none-any.whl
    some_package-0.0.0.tar.gz

    いくつかの警告メッセージが表示されましたが、作成に成功しました.ファイルと.tar.gzファイル.これらの警告を削除してみます.手順は以下のとおりです.
  • README、READMEを追加する.rst、README.txt又はREADME.mdファイル
  • 補足構成におけるurlデータ
  • 補足作成者および作成者メールボックス(または、メンテナおよびメンテナメールボックス)情報
  • また、以下の情報も追加します.
  • バージョン番号
  • ソフトウェア使用許可
  • 変更記録
  • READMEファイルはユーザーにあなたのバッグの使い方を教えます.url、著者情報は、ユーザーが問題に遭遇したときに誰に連絡するかを示します.ソフトウェア使用ライセンスは、パッケージの使用に関する注意事項(配布、貢献、多重化コードにどのような制限があるか)をユーザーに伝えます.オープンソースを望んでいない場合は、使用許可に制限を明記する必要があります.オープンソースの場合は、https://choosealicense.com/にアクセスして適切なソフトウェアライセンスを選択することを推奨します.これらの情報を追加するのにあまり時間がかかりません.以下は簡単な例です.setup.pyファイル:
    # D:\Python3Project\test\some_package_proj\setup.py
    from setuptools import setup, find_packages
    
    setup(
        name='some_package',
        description='       ',
    
        version='1.0',
        author='walker',
        author_email='[email protected]',
    
        url='https://segmentfault.com/a/1190000021065589',
    
        packages=find_packages(where='src'),
        package_dir={'': 'src'},
    )

    ライセンス条文はLICENSEファイルに入れるべきです.(walker抄のMITライセンス)
    # D:\Python3Project\test\some_package_proj\setup.py
    MIT License
    
    Copyright (c) 2014-present walker and other contributors
    
    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:
    
    The above copyright notice and this permission notice shall be included in all
    copies or substantial portions of the Software.
    
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    SOFTWARE.

    README.mdファイルの内容は以下の通りです.
    D:\Python3Project\test\some_package_proj\README.md
    # some_package:        
    `some_package` is the Python package to demostrate how easy it is 
    to create installable, maintainable, shareable packages and 
    distributions.
    \```    #        
    >>> import some_package
    >>> some_package.some_func()
    42
    \```
    That's it, really.

    私は既成のオープンソースプロジェクトからREADMEファイルをコピーし、私が必要としない条文を削除し、自分のプロジェクトの要求に応じて修正することに慣れています.厳粛な項目であれば、READMEを逐字入力することをお勧めします.個人項目はコピーして貼り付けて修正すればいいです.プロジェクトの変更を記録するログファイルを追加します.次に例を示します.
    D:\Python3Project\test\some_package_proj\CHANGELOG.md
    # Changelog
    
    All notable changes to this project will be documented in this file.
    
    ## [1.0.0] - 2019-11-21
    
    ### Added
    
    - Something be added.
    - Something be added.
    
    ### Changed
    
    - Something be changed.
    - Something be changed.
    
    ### Removed
    
    - Something be removed.
    
    ## [0.0.5] - 2019-11-15
    
    ### Added
    
    - Something be added.
    
    ### Changed
    
    - Something be changed.
    
    ### Fixed
    
    - Something be fixed.
    
    ## [0.0.4] - 2019-11-14
    
    ### Added
    
    - Something be added.
    
    ## [0.0.3] - 2019-11-13
    
    ### Added
    
    - Something be added.
    
    ### Changed
    
    - Something be changed.
    
    ### Removed
    
    - Something be removed.
    
    ## [0.0.2] - 2019-11-12
    
    ### Added
    
    - Something.
    
    ## [0.0.1] - 2019-11-11
    
    ### Added
    
    - Initial version.

    https://keepachangelog.comにアクセスして、変更ログの作成のアドバイスを読んでください.これらの変更が警告を解消するのに十分かどうかを見てみましょう.
    D:\Python3Project\test\some_package_proj
    λ python3 setup.py sdist bdist_wheel
    running sdist
    running egg_info
    creating src\some_package.egg-info
    writing src\some_package.egg-info\PKG-INFO
    writing dependency_links to src\some_package.egg-info\dependency_links.txt
    writing top-level names to src\some_package.egg-info\top_level.txt
    writing manifest file 'src\some_package.egg-info\SOURCES.txt'
    reading manifest file 'src\some_package.egg-info\SOURCES.txt'
    writing manifest file 'src\some_package.egg-info\SOURCES.txt'
    running check
    creating some_package-1.0
    creating some_package-1.0\src
    creating some_package-1.0\src\some_package
    creating some_package-1.0\src\some_package.egg-info
    copying files to some_package-1.0...
    copying README.rst -> some_package-1.0
    copying setup.py -> some_package-1.0
    copying src\some_package\__init__.py -> some_package-1.0\src\some_package
    copying src\some_package\some_module.py -> some_package-1.0\src\some_package
    copying src\some_package.egg-info\PKG-INFO -> some_package-1.0\src\some_package.egg-info
    copying src\some_package.egg-info\SOURCES.txt -> some_package-1.0\src\some_package.egg-info
    copying src\some_package.egg-info\dependency_links.txt -> some_package-1.0\src\some_package.egg-info
    copying src\some_package.egg-info\top_level.txt -> some_package-1.0\src\some_package.egg-info
    Writing some_package-1.0\setup.cfg
    creating dist
    Creating tar archive
    removing 'some_package-1.0' (and everything under it)
    running bdist_wheel
    running build
    running build_py
    creating build
    creating build\lib
    creating build\lib\some_package
    copying src\some_package\some_module.py -> build\lib\some_package
    copying src\some_package\__init__.py -> build\lib\some_package
    installing to build\bdist.win-amd64\wheel
    running install
    running install_lib
    creating build\bdist.win-amd64
    creating build\bdist.win-amd64\wheel
    creating build\bdist.win-amd64\wheel\some_package
    copying build\lib\some_package\some_module.py -> build\bdist.win-amd64\wheel\.\some_package
    copying build\lib\some_package\__init__.py -> build\bdist.win-amd64\wheel\.\some_package
    running install_egg_info
    Copying src\some_package.egg-info to build\bdist.win-amd64\wheel\.\some_package-1.0-py3.6.egg-info
    running install_scripts
    adding license file "LICENSE" (matched pattern "LICEN[CS]E*")
    creating build\bdist.win-amd64\wheel\some_package-1.0.dist-info\WHEEL
    creating 'dist\some_package-1.0-py3-none-any.whl' and adding 'build\bdist.win-amd64\wheel' to it
    adding 'some_package/__init__.py'
    adding 'some_package/some_module.py'
    adding 'some_package-1.0.dist-info/LICENSE'
    adding 'some_package-1.0.dist-info/METADATA'
    adding 'some_package-1.0.dist-info/WHEEL'
    adding 'some_package-1.0.dist-info/top_level.txt'
    adding 'some_package-1.0.dist-info/RECORD'
    removing build\bdist.win-amd64\wheel
    D:\Python3Project\test\some_package_proj
    λ dir /B dist
    some_package-0.0.0-py3-none-any.whl
    some_package-0.0.0.tar.gz

    はい、警告はありません.今すぐできます.ファイルと.tar.gzファイルを同じディレクトリに配置し、pip installを実行します.
    D:\Python3Project\test\some_package_proj
    λ mkdir .\packages
    
    D:\Python3Project\test\some_package_proj
    λ copy .\dist\some_package-1.0-py3-none-any.whl .\packages\
                1    。
    
    D:\Python3Project\test\some_package_proj
    λ copy .\dist\some_package-1.0.tar.gz .\packages\
                1    。
    D:\Python3Project\test\some_package_proj
    λ pip3 install --no-index --find-links=.\packages\ some_package
    Looking in links: .\packages\
    Processing d:\python3project\test\some_package_proj\packages\some_package-1.0-py3-none-any.whl
    Installing collected packages: some-package
    Successfully installed some-package-1.0
    
    D:\Python3Project\test\some_package_proj
    λ pip3 install --no-index --find-links=.\packages\ some_package==1.0
    Looking in links: .\packages\
    Requirement already satisfied: some_package==1.0 in 
    c:\program files\python36\lib\site-packages (1.0)

    PyPIからインストールするように簡単にインストールできるように、ローカルプロジェクトに独自のパッケージを作成できます.
    PyPIからインストールできるパッケージの作成
    Creating a PyPI-Installable Package
    PyPIで自分のパッケージを公開する場合はsetup.pyにより多くの構成を追加します.また、TwineのようなツールでパッケージをPyPIにプッシュする必要があります.Twineは、PyPIとより簡単に、より安全に対話できるツールのセットです.HTTPS認証によりPyPI鍵情報を保護し、パケットをPyPIに転送する責任を負います.これらの内容は本書の範囲を超えています.詳細はPython Packaging User Guide(Pythonプログラムユーザー配布ガイド)とPythonドキュメントのPyPIに関する部分を参照してください.