アプリケーションをリリースしてみよう
コマンドを作成してリリースする
はじめにディレクトリ myapp に、typer を使った簡単なスクリプトがあるとして、
説明していきましょう。
code: myapp.py
import typer
app = typer.Typer()
@app.command()
def hello(count: int = typer.Option(1, '-C', '--count',
help='Number of greetings.'),
name: str = typer.Option(..., prompt='Your Name',
help='The person to greet.'),
):
"""COUNTで与えた回数だけHelloする"""
for x in range(count):
typer.echo(f'Hello {name}')
このファイルと同じディレクトリに、次のような setup.py を作成します。
code: setup.py
from setuptools import setup
setup(
name='myapp', # コマンド名
version='0.1', # バージョン
install_requires=[ # 動作に必要なモジュール
'typer',
],
entry_points='''
myapp=myapp:app
''',
)
entry_points パラメタの console_scripts がカギです。
コマンド myapp はモジュール myappのapp() をインポートして実行するということを表しています。
今時点では、ディレクトリ myapp には次の2つのファイルがあるだけです。
code: bash
$ tree -L 2 .
.
├── myapp.py
└── setup.py
コマンド作成の準備はこれだけです。
pip install --editable . を実行すると、今作成したコマンド myapp が使えるようになります。
code: zsh
% pip install --editable .
Obtaining file:///Users/goichiiisaka/Projects/Python.Osaka/Poetry/typer_tutorial/myapp
Requirement already satisfied: typer in /Users/goichiiisaka/anaconda3/envs/py38/lib/python3.8/site-packages (from myapp==0.1) (0.3.2)
Requirement already satisfied: click<7.2.0,>=7.1.1 in /Users/goichiiisaka/anaconda3/envs/py38/lib/python3.8/site-packages (from typer->myapp==0.1) (7.1.2)
Installing collected packages: myapp
Running setup.py develop for myapp
Successfully installed myapp
$ which myapp
/Users/goichiiisaka/anaconda3/envs/py38/bin/myapp
$ myapp --help
COUNTで与えた回数だけHelloする
Options:
-C, --count INTEGER Number of greetings.
--name TEXT The person to greet.
--help Show this message and exit.
$ myapp --name Python
Hello Python!
これで、次のようなコードを毎回書かなくても済みますね。
code: click_myapp_tail.py
if __name__ == '__main__':
app()
ディレクトリ myapp は次のように必要なファイルが自動的に作成されています。
code: bash
$ tree -L 2 .
.
├── click_myapp.py
├── myapp.egg-info
│ ├── PKG-INFO
│ ├── SOURCES.txt
│ ├── dependency_links.txt
│ ├── entry_points.txt
│ ├── requires.txt
│ └── top_level.txt
└── setup.py
コマンドの削除
アプリケーションを削除するときも簡単で、pip uninstall アプリケーション名 を実行するだけです。
code: bash
$ pip uninstall myapp
Found existing installation: myapp 0.1
Uninstalling myapp-0.1:
Would remove:
/Users/goichiiisaka/anaconda3/envs/py38/bin/myapp
/Users/goichiiisaka/anaconda3/envs/py38/lib/python3.8/site-packages/myapp.egg-link
Proceed (y/n)? y
Successfully uninstalled myapp-0.1
console_scripts の中身をみてみよう
コマンド myapp は次のようになっています。
code: myapp
# EASY-INSTALL-ENTRY-SCRIPT: 'myapp','console_scripts','myapp'
import re
import sys
# for compatibility with easy_install; see #2198 __requires__ = 'myapp'
try:
from importlib.metadata import distribution
except ImportError:
try:
from importlib_metadata import distribution
except ImportError:
from pkg_resources import load_entry_point
def importlib_load_entry_point(spec, group, name):
dist_name, _, _ = spec.partition('==')
matches = (
entry_point
for entry_point in distribution(dist_name).entry_points
if entry_point.group == group and entry_point.name == name
)
return next(matches).load()
globals().setdefault('load_entry_point', importlib_load_entry_point)
if __name__ == '__main__':
sys.argv0 = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv0) sys.exit(load_entry_point('myapp', 'console_scripts', 'myapp')())
このとき、__requires__ = 'myapp' とされているモジュールは何処からロードするのでしょうか?
実際のファイルがある場所を指示するmyapp.egg-link が作られています。
この内容は pip install --editable . を実行したディレクトリです。
code: zsh
% DIR=/Users/goichiiisaka/anaconda3/envs/py38
$ find $DIR/lib/python3.8/site-packages/ | grep myapp
/Users/goichiiisaka/anaconda3/envs/py38/lib/python3.8/site-packages/myapp.egg-link
$ cat /Users/goichiiisaka/anaconda3/envs/py38/lib/python3.8/site-packages//myapp.egg-link
/Users/goichiiisaka/Projects/Python.Osaka/Poetry/typer_tutorial/myapp
$ $ pwd
/Users/goichiiisaka/Projects/Python.Osaka/Poetry/typer_tutorial/myapp
$ ls
__pycache__ click_myapp.py myapp.egg-info setup.py
参考: