やりたいこと

  • Pythonモジュールをパッケージ化
  • モジュールのテストのために、pytestのディレクトリ構成(src、test)を使用
  • モジュールを使った、コマンドラインツールをインストール

作成するファイル一覧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
├── LICENSE
├── Makefile
├── README.md
├── setup.cfg
├── setup.py
├── src
│ ├── consoleapp
│ │ ├── __init__.py
│ │ └── cli.py
│ └── mypackage
│ ├── __init__.py
│ └── mymodule.py
└── test
└── test_mypackage.py

setup.py

setup.pysetup()を呼ぶだけの内容。

1
2
3
from setuptools import setup

setup()

setup.cfg

setup.cfgはパッケージに関する情報を記述する。
[metadata]は自身の内容を記述する。通常gitリポジトリで作成するLICENSEREADME.mdは流用する形にしている。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[metadata]
name = console_scripts
version = attr: consoleapp.__version__
url = https://xxxxxxxxxxxxxxxxxxxxx
author = XXXXXXXXXX
author_email = xxxxxxx@xxxxxxxxxxxx
license_file = LICENSE
description = console scripts
long_description = file: README.md
long_description_content_type = text/markdown

[options]
zip_safe = False
package_dir=
=src
packages = find:
install_requires =

[options.extras_require]
dev =
pytest

[options.packages.find]
where=src

[options.entry_points]
console_scripts =
consapp = consoleapp.cli:main

srcディレクトリ以下にソースコードを置くための記述

package_dirsrcディレクトリを指定する。
パッケージを探索もsrcディレクトリを参照する。

1
2
3
4
5
6
7
[options]
package_dir=
=src
packages = find:

[options.packages.find]
where=src

pytestでテストするために開発時はpytestパッケージをインストールする

[options.extras_require]で指定したオプションを使って開発時のインストールでpytestパッケージを要求パッケージにする。

1
2
3
[options.extras_require]
dev =
pytest

開発時は以下のコマンドで、指定した要求パッケージをインストールすることができる。

1
pip install -e .[dev]

コマンドラインツールをインストールする

[options.entry_points]でコマンドラインツールとしてインストールする。
下の設定例ではconsappというコマンド名で/usr/local/binにインストールされる。
consoleapp:mainconsoleapp.pyにあるmainを実行する。

1
2
3
[options.entry_points]
console_scripts =
consapp = consoleapp.cli:main

バージョン情報を参照する

バージョン情報を__init__.pyに記述。

1
__version__ = '0.0.1'

記述したバージョン情報はattrで参照できる。

1
version = attr: consoleapp.__version__

サンプルコード(src/mypackage/mymodule.py)

mypackage/mymodule.pyとして以下の内容を作成。

1
2
def add(x, y):
return x + y

サンプルコード(src/consoleapp/cli.py)

cli.pymypackage/mymodule.pyを使って結果を表示するmain()が定義している。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import random
import mypackage.mymodule

def main():
x = random.random()
y = random.random()

print("X={}".format(x))
print("Y={}".format(y))

print("X+Y={}".format(mypackage.mymodule.add(x, y)))

if __name__ == '__main__':
main()

サンプルテストコード(test/test_mypackage.py)

test/test_mypackage.pyにテストコードを置く。
pytestはファイル名にtestを含むものを処理していく。

1
2
3
4
import mypackage.mymodule

def test_mypackage():
assert mypackage.mymodule.add(1,1) == 2

パッケージ作成と実行例

dev指定でインストールしてpytestを実行する

[dev]オプション付きでインストールすると、指定したpytestパッケージもインストールされる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ pip install -e .[dev]
Obtaining file:///work/setuptools/min_package
Collecting pytest
Downloading pytest-5.4.1-py3-none-any.whl (246 kB)
|████████████████████████████████| 246 kB 3.2 MB/s
Collecting more-itertools>=4.0.0
Downloading more_itertools-8.2.0-py3-none-any.whl (43 kB)
|████████████████████████████████| 43 kB 2.1 MB/s
Collecting wcwidth
Downloading wcwidth-0.1.9-py2.py3-none-any.whl (19 kB)
Collecting pluggy<1.0,>=0.12
Downloading pluggy-0.13.1-py2.py3-none-any.whl (18 kB)
Collecting attrs>=17.4.0
Downloading attrs-19.3.0-py2.py3-none-any.whl (39 kB)
Collecting py>=1.5.0
Downloading py-1.8.1-py2.py3-none-any.whl (83 kB)
|████████████████████████████████| 83 kB 2.2 MB/s
Collecting packaging
Downloading packaging-20.3-py2.py3-none-any.whl (37 kB)
Requirement already satisfied: six in /usr/local/lib/python3.8/site-packages (from packaging->pytest->console-scripts==0.0.1) (1.14.0)
Collecting pyparsing>=2.0.2
Downloading pyparsing-2.4.7-py2.py3-none-any.whl (67 kB)
|████████████████████████████████| 67 kB 5.1 MB/s
Installing collected packages: more-itertools, wcwidth, pluggy, attrs, py, pyparsing, packaging, pytest, console-scripts
Running setup.py develop for console-scripts
Successfully installed attrs-19.3.0 console-scripts more-itertools-8.2.0 packaging-20.3 pluggy-0.13.1 py-1.8.1 pyparsing-2.4.7 pytest-5.4.1 wcwidth-0.1.9

pytestでテスト実行。以下はキャッシュを残さないオプション付きで実行している。

1
2
3
4
5
6
7
8
9
$ pytest -p no:cacheprovider
================================ test session starts ================================
platform linux -- Python 3.8.2, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /work/setuptools/min_package
collected 1 item

test/test_mypackage.py [100%]

================================= 1 passed in 0.07s =================================

インストールしてコマンドラインツールを実行する

インストールすると作成したPythonパッケージとconsappコマンドがインストールされる。

1
2
3
4
5
$ pip install -e .
Obtaining file:///work/setuptools/min_package
Installing collected packages: console-scripts
Running setup.py develop for console-scripts
Successfully installed console-scripts

/usr/local/bin/にインストールされパスも通った状態になっている。

1
2
3
4
$ consapp
X=0.8166454250641093
Y=0.9771692906142968
X+Y=1.7938147156784061

GitHubからインストールする

HTTPでインストールする場合

1
pip install git+https://github.com/xxxxxxxxxxx/xxxxxx.git

SSHでインストールする場合

1
pip install git+ssh://git@github.com/xxxxxxxxxxx/xxxxxx.git

参考