いくつかの便利な機能をコマンドとして使用したい。そのために、click
ライブラリをテストしています。 3つの元の関数を定義し、click.command
:
import click
import os, sys
@click.command()
@click.argument('content', required=False)
@click.option('--to_stdout', default=True)
def add_name(content, to_stdout=False):
if not content:
content = ''.join(sys.stdin.readlines())
result = content + "\n\tadded name"
if to_stdout is True:
sys.stdout.writelines(result)
return result
@click.command()
@click.argument('content', required=False)
@click.option('--to_stdout', default=True)
def add_surname(content, to_stdout=False):
if not content:
content = ''.join(sys.stdin.readlines())
result = content + "\n\tadded surname"
if to_stdout is True:
sys.stdout.writelines(result)
return result
@click.command()
@click.argument('content', required=False)
@click.option('--to_stdout', default=False)
def add_name_and_surname(content, to_stdout=False):
result = add_surname(add_name(content))
if to_stdout is True:
sys.stdout.writelines(result)
return result
このようにして、3つのコマンドを生成できますadd_name
、add_surname
およびadd_name_and_surname
を使って setup.py
ファイルとpip install --editable .
その後、私はパイプすることができます:
$ echo "original content" | add_name | add_surname
original content
added name
added surname
ただし、異なるクリックコマンドを関数として作成する場合、解決する必要があるわずかな問題が1つあります。
$echo "original content" | add_name_and_surname
Usage: add_name_and_surname [OPTIONS] [CONTENT]
Error: Got unexpected extra arguments (r i g i n a l c o n t e n t
)
なぜ機能しないのかわからないので、これが必要ですadd_name_and_surname
を呼び出すコマンドadd_name
およびadd_surname
コマンドとしてではなく関数として、そうでなければ、ライブラリ関数とコマンドの両方として関数を使用するという私の本来の目的を無効にします。
クリックデコレータにより、引数を指定するだけでは関数を呼び出すことができなくなります。 Context クラスは、ここでは特にあなたの友達です:
したがって、add_name_and_surnameのコードは次のようになります。
@click.command()
@click.argument('content', required=False)
@click.option('--to_stdout', default=False)
@click.pass_context
def add_name_and_surname(ctx, content, to_stdout=False):
result = ctx.invoke(add_surname, content=ctx.forward(add_name))
if to_stdout is True:
sys.stdout.writelines(result)
return result
リファレンス: http://click.pocoo.org/6/advanced/#invoking-other-commands
add_name()
とadd_surname()
を別の関数から直接呼び出す場合、実際に装飾されたバージョンを呼び出すため、期待される引数は定義したとおりではない場合があります( Pythonの関数からデコレータを取り除く方法 理由の詳細については)。
元の関数を装飾せずに維持し、それらの薄いクリック固有のラッパーを作成するように、実装を変更することをお勧めします。たとえば:
def add_name(content, to_stdout=False):
if not content:
content = ''.join(sys.stdin.readlines())
result = content + "\n\tadded name"
if to_stdout is True:
sys.stdout.writelines(result)
return result
@click.command()
@click.argument('content', required=False)
@click.option('--to_stdout', default=True)
def add_name_command(content, to_stdout=False):
return add_name(content, to_stdout)
その後、これらの関数を直接呼び出すか、setup.pyで作成されたCLIラッパースクリプトを介して呼び出すことができます。
これは冗長に思えるかもしれませんが、実際にはおそらく正しい方法です:1つの関数はビジネスロジックを表し、もう1つ(クリックコマンド)はコマンドラインを介してこのロジックを公開する「コントローラー」です(たとえば、Webサービスを介して同じロジックを公開する関数もあります)。
実際、それらを別々のPythonモジュール-必要に応じて他のインターフェイスに置き換えることができる「コア」ロジックとクリック固有の実装に配置することをお勧めします。