diff --git a/docs/tutorial/arguments/default.ja.md b/docs/tutorial/arguments/default.ja.md new file mode 100644 index 0000000000..4174e031ac --- /dev/null +++ b/docs/tutorial/arguments/default.ja.md @@ -0,0 +1,102 @@ +# デフォルト値付き CLI 引数 + +同じ `typer.Argument()` を使ってデフォルト値を設定することもできます。 + +そうすると、その *CLI 引数* は省略可能になるだけでなく、デフォルト値も持つようになります。 + +## デフォルト値を持つ省略可能な *CLI 引数* + +`typer.Argument()` を使って、*CLI 引数* に `None` 以外のデフォルト値を持たせることもできます。 + +{* docs_src/arguments/default/tutorial001_an_py310.py hl[9] *} + +/// tip + +この場合、値は利用者が渡す `str` か、デフォルト値 `"Wade Wilson"` のどちらかで、どちらも `str` です。したがって、値が `None` になることはないので、`Optional[str]` を使う必要はありませんし、使うべきでもありません。 + +`Optional[something]` は、Python に「その値は `None` になり得る」と伝えるものです。ただし `Optional` を使っても、Typer に対して値が必須かどうかを伝えることにはなりません。 + +/// + +確認してみましょう。 + +
+ +```console +// help を確認します +$ python main.py --help + +// [default: Wade Wilson] ✨ に注目してください +Usage: main.py [OPTIONS] [NAME] + +Arguments: + [NAME] [default: Wade Wilson] + +Options: + --help Show this message and exit. + +// 省略可能な CLI 引数なし +$ python main.py + +Hello Wade Wilson + +// CLI 引数を 1 つ渡す +$ python main.py Camila + +Hello Camila +``` + +
+ +## 動的なデフォルト値 + +`default_factory` 引数に関数を渡せば、デフォルト値を動的に生成することもできます。 + +{* docs_src/arguments/default/tutorial002_an_py310.py hl[9:10,14] *} + +この場合は、毎回ランダムな `str` を返す `get_name` 関数を作成しています。 + +そして、それを `typer.Argument()` の最初の関数引数として渡しています。 + +/// tip + +`default_factory` の "factory" という言葉は、単に「デフォルト値を作る関数」という意味です。 + +/// + +確認してみましょう。 + +
+ +```console +// help を確認します +$ python main.py --help + +Usage: main.py [OPTIONS] [NAME] + +Arguments: + [NAME] [default: (dynamic)] + +Options: + --help Show this message and exit. + +// 何度か試してみてください。毎回ランダムなデフォルト値が使われます +$ python main.py + +Hello Deadpool + +$ python main.py + +Hello Hiro + +$ python main.py + +Hello Rick + +// 今度は CLI 引数に値を渡します +$ python main.py Camila + +Hello Camila +``` + +
diff --git a/docs/tutorial/arguments/envvar.ja.md b/docs/tutorial/arguments/envvar.ja.md new file mode 100644 index 0000000000..926e6f242d --- /dev/null +++ b/docs/tutorial/arguments/envvar.ja.md @@ -0,0 +1,118 @@ +# 環境変数付き CLI 引数 + +*CLI 引数* がコマンドラインで渡されなかった場合に、環境変数から値を読むよう設定することもできます。 + +/// tip + +環境変数について詳しくは、[Environment Variables](../../environment-variables.md){.internal-link target=_blank} を参照してください。 + +/// + +そのためには、`typer.Argument()` の `envvar` パラメータを使います。 + +{* docs_src/arguments/envvar/tutorial001_an_py310.py hl[9] *} + +この場合、*CLI 引数* `name` のデフォルト値は `"World"` ですが、コマンドラインで値が渡されなければ、環境変数 `AWESOME_NAME` に設定された値も読み取ります。 + +
+ +```console +// help を確認 +$ python main.py --help + +Usage: main.py [OPTIONS] [NAME] + +Arguments: + [NAME] [env var: AWESOME_NAME;default: World] + +Options: + --help Show this message and exit. + +// CLI 引数なしで実行 +$ python main.py + +Hello Mr. World + +// 今度は CLI 引数を渡す +$ python main.py Czernobog + +Hello Mr. Czernobog + +// 次に環境変数を使う +$ AWESOME_NAME=Wednesday python main.py + +Hello Mr. Wednesday + +// CLI 引数は env var より優先される +$ AWESOME_NAME=Wednesday python main.py Czernobog + +Hello Mr. Czernobog +``` + +
+ +## 複数の環境変数 + +環境変数は 1 つに限りません。コマンドラインで値が渡されなかったときに使える環境変数のリストを宣言できます。 + +{* docs_src/arguments/envvar/tutorial002_an_py310.py hl[10] *} + +確認してみましょう。 + +
+ +```console +// help を確認 +$ python main.py --help + +Usage: main.py [OPTIONS] [NAME] + +Arguments: + [NAME] [env var: AWESOME_NAME, GOD_NAME;default: World] + +Options: + --help Show this message and exit. + +// 1 つ目の env var を試す +$ AWESOME_NAME=Wednesday python main.py + +Hello Mr. Wednesday + +// 2 つ目の env var を試す +$ GOD_NAME=Anubis python main.py + +Hello Mr. Anubis +``` + +
+ +## help テキストから env var を隠す + +デフォルトでは、使用される環境変数は help テキストに表示されますが、`show_envvar=False` で無効にできます。 + +{* docs_src/arguments/envvar/tutorial003_an_py310.py hl[11] *} + +確認してみましょう。 + +
+ +```console +// help を確認 +$ python main.py --help + +// env var は表示されない +Usage: main.py [OPTIONS] [NAME] + +Arguments: + [NAME] [default: World] + +Options: + --help Show this message and exit. + +// それでも env var は使える +$ AWESOME_NAME=Wednesday python main.py + +Hello Mr. Wednesday +``` + +
diff --git a/docs/tutorial/arguments/help.ja.md b/docs/tutorial/arguments/help.ja.md new file mode 100644 index 0000000000..62f787da00 --- /dev/null +++ b/docs/tutorial/arguments/help.ja.md @@ -0,0 +1,219 @@ +# help 付き CLI 引数 + +*First Steps* セクションでは、関数の docstring に書くことで、CLI アプリやコマンドの help を追加する方法を見ました。 + +その最後の例は次のようなものでした。 + +{* docs_src/first_steps/tutorial006_py310.py *} + +`typer.Argument()` の使い方も分かったので、今度は *CLI 引数* 自体に対する説明を追加してみましょう。 + +## *CLI 引数* に `help` テキストを追加する + +`help` パラメータを使うと、*CLI 引数* に help テキストを追加できます。 + +{* docs_src/arguments/help/tutorial001_an_py310.py hl[9] *} + +すると、自動生成される `--help` オプションで使われます。 + +
+ +```console +$ python main.py --help + +// 下の Arguments セクションを見てください 🚀 +Usage: main.py [OPTIONS] NAME + +Arguments: + NAME The name of the user to greet [required] + +Options: + --help Show this message and exit. +``` + +
+ +## help テキストと docstring を組み合わせる + +もちろん、この `help` は docstring と組み合わせることもできます。 + +{* docs_src/arguments/help/tutorial002_an_py310.py hl[9:12] *} + +`--help` オプションには、すべての情報がまとめて表示されます。 + +
+ +```console +$ python main.py --help + +// docstring の help テキストと Arguments の両方が入っていることに注目してください 📝 +Usage: main.py [OPTIONS] NAME + + Say hi to NAME very gently, like Dirk. + +Arguments: + NAME The name of the user to greet [required] + +Options: + --help Show this message and exit. +``` + +
+ +## デフォルト値の help + +`"World"` のように、*CLI 引数* にデフォルト値がある場合: + +{* docs_src/arguments/help/tutorial003_an_py310.py hl[9] *} + +そのデフォルト値が help テキストに表示されます。 + +
+ +```console +$ python main.py --help + +// [default: World] が表示されていることに注目してください 🔍 +Usage: main.py [OPTIONS] [NAME] + + Say hi to NAME very gently, like Dirk. + +Arguments: + [NAME] Who to greet [default: World] + +Options: + --help Show this message and exit. +``` + +
+ +ただし、`show_default=False` を使えば、これを無効にできます。 + +{* docs_src/arguments/help/tutorial004_an_py310.py hl[11] *} + +すると、デフォルト値は表示されません。 + +
+ +```console +$ python main.py --help + +// 今は [default: World] がないことに注目してください 🔥 +Usage: main.py [OPTIONS] [NAME] + + Say hi to NAME very gently, like Dirk. + +Arguments: + [NAME] Who to greet + +Options: + --help Show this message and exit. +``` + +
+ +## カスタムデフォルト文字列 + +同じ `show_default` で `bool` の代わりに独自の文字列を渡すと、help テキストに表示するデフォルト値をカスタマイズできます。 + +{* docs_src/arguments/help/tutorial005_an_py310.py hl[13] *} + +すると、その文字列が help テキストで使われます。 + +
+ +```console +$ python main.py --help + +Usage: main.py [OPTIONS] [NAME] + +Arguments: + [NAME] Who to greet [default: (Deadpoolio the amazing's name)] + + +Options: + --help Show this message and exit. + +// 実際のデフォルト値 "Wade Wilson" ではなく "(Deadpoolio the amazing's name)" が表示されています +``` + +
+ +## カスタム help 名(`metavar`) + +生成される help テキストで *CLI 引数* を表す表示名もカスタマイズできます。 + +デフォルトでは、宣言した名前と同じものが大文字で使われます。 + +つまり、次のように宣言すると: + +```Python +name: str +``` + +次のように表示されます。 + +``` +NAME +``` + +これを変更したい場合は、`typer.Argument()` の `metavar` パラメータを使います。 + +たとえば、デフォルトの `NAME` ではなく、小文字の `username` を使いたいとします。しかも、どこにでも ✨ emojis ✨ を入れたい場合: + +{* docs_src/arguments/help/tutorial006_an_py310.py hl[9] *} + +生成される help テキストでは、`NAME` の代わりに `✨username✨` が表示されます。 + +
+ +```console +$ python main.py --help + +Usage: main.py [OPTIONS] [✨username✨] + +Arguments: + [✨username✨] [default: World] + +Options: + --help Show this message and exit. +``` + +
+ +## *CLI 引数* の help パネル + +`--help` オプションを使うときに、*CLI 引数* の help 情報を別々のパネルに分けて表示したい場合があります。 + +[Printing and Colors](../printing.md){.internal-link target=_blank} のドキュメントで説明したように Rich をインストールしていれば、`rich_help_panel` パラメータに表示先パネル名を指定できます。 + +{* docs_src/arguments/help/tutorial007_an_py310.py hl[12,16] *} + +`--help` オプションを確認すると、`rich_help_panel` を設定していない *CLI 引数* 用に、デフォルトで `Arguments` というパネルが表示されます。 + +その後に、`rich_help_panel` パラメータでカスタムパネルを指定した *CLI 引数* 用の別パネルが表示されます。 + +
+ +```console +$ python main.py --help + + Usage: main.py [OPTIONS] NAME [LASTNAME] [AGE] + + Say hi to NAME very gently, like Dirk. + +╭─ Arguments ───────────────────────────────────────────────────────╮ +* name TEXT Who to greet [default: None] [required] │ +╰───────────────────────────────────────────────────────────────────╯ +╭─ Secondary Arguments ─────────────────────────────────────────────╮ +│ lastname [LASTNAME] The last name │ +│ age [AGE] The user's age │ +╰───────────────────────────────────────────────────────────────────╯ +╭─ Options ─────────────────────────────────────────────────────────╮ +--help Show this message and exit. │ +╰───────────────────────────────────────────────────────────────────╯ +``` + +
+ +この例では、`Secondary Arguments` という名前のカスタム *CLI 引数* パネルを使っています。 diff --git a/docs/tutorial/arguments/index.ja.md b/docs/tutorial/arguments/index.ja.md new file mode 100644 index 0000000000..a9204d0551 --- /dev/null +++ b/docs/tutorial/arguments/index.ja.md @@ -0,0 +1,5 @@ +# CLI 引数 + +次のいくつかのセクションでは、*CLI 引数* の動きを調整する方法を見ていきます。 + +*CLI 引数* を省略可能にしたり、*CLI 引数* に組み込みの help を追加したりします。 diff --git a/docs/tutorial/arguments/optional.ja.md b/docs/tutorial/arguments/optional.ja.md new file mode 100644 index 0000000000..7f679e9802 --- /dev/null +++ b/docs/tutorial/arguments/optional.ja.md @@ -0,0 +1,240 @@ +# 省略可能な CLI 引数 + +前に説明したとおり、*デフォルトでは*: + +* *CLI オプション* は **省略可能** +* *CLI 引数* は **必須** + +繰り返しになりますが、これは *デフォルトでの* 挙動であり、多くの CLI プログラムやシステムでの慣例でもあります。 + +ただし、これは変更できます。 + +実際には、**省略可能** な *CLI 引数* を持つほうが、**必須** の *CLI オプション* を持つよりもずっと一般的です。 + +それがどのように役立つかの例として、`ls` という CLI プログラムの動きを見てみましょう。 + +
+ +```console +// ただ入力すると +$ ls + +// ls は現在のディレクトリ内のファイルとディレクトリを一覧表示します +typer tests README.md LICENSE + +// ただし、省略可能な CLI 引数も受け取れます +$ ls ./tests/ + +// すると ls は、その CLI 引数で指定されたディレクトリ内のファイルとディレクトリを一覧表示します +__init__.py test_tutorial +``` + +
+ +## *CLI 引数* の別の宣言方法 + +[First Steps](../first-steps.md#add-a-cli-argument){.internal-link target=_blank} では、*CLI 引数* を追加する方法を見ました。 + +{* docs_src/first_steps/tutorial002_py310.py hl[4] *} + +ここで、同じ *CLI 引数* を作る別の方法を見てみましょう。 + +{* docs_src/arguments/optional/tutorial000_an_py310.py hl[6] *} + +あるいは、`Typer()` instance を明示的に作る形では次のようになります。 + +{* docs_src/arguments/optional/tutorial001_an_py310.py hl[9] *} + +/// info + +Typer はバージョン 0.9.0 で `Annotated` のサポートを追加し、以後それを推奨するようになりました。 + +それより古いバージョンを使っている場合、`Annotated` を使おうとするとエラーになります。 + +`Annotated` を使う前に、Typer のバージョンを少なくとも 0.9.0 へ更新してください。 + +/// + +以前は、次のような関数パラメータでした。 + +```Python +name: str +``` + +それを今度は `Annotated` で包みます。 + +```Python +name: Annotated[str] +``` + +この 2 つは同じ意味で、`Annotated` はそのために標準 Python に用意されています。 + +ただし `Annotated` を使う後者の書き方では、**Typer** が利用できる追加のメタデータを渡せます。 + +```Python +name: Annotated[str, typer.Argument()] +``` + +これで `name` が *CLI 引数* であることを明示しています。型は依然として `str` のままで、デフォルト値を持たないので必須のままです。 + +ここでやっていることは、以前と同じ **必須** の *CLI 引数* を作ることです。 + +
+ +```console +$ python main.py + +Usage: main.py [OPTIONS] NAME +Try "main.py --help" for help. + +Error: Missing argument 'NAME'. +``` + +
+ +まだそれほど便利ではありませんが、正しく動作しています。 + +そして、 + +```Python +name: Annotated[str, typer.Argument()] +``` + +のように **必須** の *CLI 引数* を宣言する方法は、 + +```Python +name: str +``` + +とまったく同じように動きます。 + +これはあとで役立ちます。 + +## *CLI 引数* を省略可能にする + +さて、ここで本題の、省略可能な *CLI 引数* を見ていきます。 + +*CLI 引数* を省略可能にするには、`typer.Argument()` を使い、"default" 値を与えます。たとえば `"World"` のようにします。 + +{* docs_src/arguments/optional/tutorial002_an_py310.py hl[9] *} + +これで次のようになります。 + +```Python +name: Annotated[str, typer.Argument()] = "World" +``` + +`typer.Argument()` を使っているので、**Typer** はこれが *CLI 引数* だと分かります(*必須* か *省略可能* かに関係なく)。 + +help を確認してみましょう。 + +
+ +```console +// まず help を確認します +$ python main.py --help + +Usage: main.py [OPTIONS] [NAME] + +Arguments: + [NAME] + +Options: + --help Show this message and exit. +``` + +
+ +/// tip + +`NAME` は依然として *CLI 引数* であり、"`Usage: main.py` ..." の部分に表示されていることに注目してください。 + +また、以前は単に `NAME` だったのに対し、今は `[NAME]` のように角括弧で囲まれていて、これが **必須** ではなく **省略可能** であることを表しています。 + +/// + +では、実行して試してみましょう。 + +
+ +```console +// CLI 引数なし +$ python main.py + +Hello World! + +// 省略可能な CLI 引数を 1 つ渡す +$ python main.py Camila + +Hello Camila +``` + +
+ +/// tip + +ここでの "`Camila`" は、省略可能な *CLI 引数* であって *CLI オプション* ではありません。"`--name Camila`" のような形ではなく、単に "`Camila`" をプログラムへ直接渡しているからです。 + +/// + +## 古い別方式: `typer.Argument()` をデフォルト値として使う + +**Typer** は、追加のメタデータ付きで *CLI 引数* を宣言する、もう 1 つの古い書き方もサポートしています。 + +`Annotated` を使う代わりに、`typer.Argument()` をデフォルト値として使えます。 + +{* docs_src/arguments/optional/tutorial001_py310.py hl[7] *} + +/// tip + +可能なら `Annotated` 版を使うほうがよいです。 + +/// + +以前は、`name` にデフォルト値がなかったので、Python の意味では **必須パラメータ** でした。 + +デフォルト値として `typer.Argument()` を使うと、**Typer** も同様にこれを **必須** の *CLI 引数* として扱います。 + +次のように変更しました。 + +```Python +name: str = typer.Argument() +``` + +しかし、今度は `typer.Argument()` が関数パラメータの「デフォルト値」になるため、Python の意味では「もはや必須ではない」ことになります。 + +関数パラメータに Python 側のデフォルト値があるかどうかで必須性やデフォルト値を判断できなくなるため、`typer.Argument()` は最初の引数として `default` パラメータを受け取り、それで同じ目的を果たします。 + +`default` 引数に何も渡さないのは、必須として扱うのと同じです。ただし `typer.Argument(default=...)` のように `...` を渡して、明示的に *required* とすることもできます。 + +```Python +name: str = typer.Argument(default=...) +``` + +/// info + +もしこの `...` を見たことがなければ、それは特殊な単一の値で、Python に含まれる "Ellipsis" です。 + +/// + +{* docs_src/arguments/optional/tutorial003_py310.py hl[7] *} + +同様に、たとえば `"World"` のような別の `default` 値を渡せば、省略可能にできます。 + +{* docs_src/arguments/optional/tutorial002_py310.py hl[7] *} + +`typer.Argument(default="World")` に渡した最初のパラメータ(新しい "default" 値)が `"World"` なので、**Typer** はこれを **省略可能** な *CLI 引数* だと判断します。コマンドラインで呼び出すときに値が与えられなければ、その `"World"` がデフォルト値として使われます。 + +`default` 引数は最初のものなので、`default=` を明示せずに値を渡しているコードを見ることもあるでしょう。たとえば次のような形です。 + +```Python +name: str = typer.Argument(...) +``` + +あるいは次のような形です。 + +```Python +name: str = typer.Argument("World") +``` + +ただし繰り返しになりますが、可能なら `Annotated` を使うようにしてください。そのほうが Python の意味としても **Typer** の意味としても同じになり、こうした細部を覚えなくて済みます。 diff --git a/docs/tutorial/arguments/other-uses.ja.md b/docs/tutorial/arguments/other-uses.ja.md new file mode 100644 index 0000000000..4bbd9bc8f0 --- /dev/null +++ b/docs/tutorial/arguments/other-uses.ja.md @@ -0,0 +1,7 @@ +# その他の用途 + +`typer.Argument()` には、他にもいくつかの用途があります。 + +たとえば、データバリデーションに使ったり、別の機能を有効にしたりできます。 + +そうした使い方については、このドキュメントの後のほうで説明します。 diff --git a/docs/tutorial/first-steps.ja.md b/docs/tutorial/first-steps.ja.md new file mode 100644 index 0000000000..9f01ce70fe --- /dev/null +++ b/docs/tutorial/first-steps.ja.md @@ -0,0 +1,260 @@ +# はじめの一歩 + +## もっともシンプルな例 + +もっともシンプルな **Typer** のファイルは、次のようになります。 + +{* docs_src/first_steps/tutorial001_py310.py *} + +これを `main.py` というファイルにコピーしてください。 + +試してみましょう。 + +
+ +```console +$ python main.py + +Hello World + +// ただ "Hello World" を表示するだけです。 + +// 次に --help を確認します +$ python main.py --help + + Usage: main.py [OPTIONS] + +╭─ Options ─────────────────────────────────────────╮ +--help Show this message │ +│ and exit. │ +╰───────────────────────────────────────────────────╯ +``` + +
+ +...とはいえ、このプログラムはまだあまり実用的ではありません。少し拡張してみましょう。 + +## **CLI argument** とは + +ここでは **CLI argument** という言葉を、CLI アプリケーションに特定の順序で渡される **CLI パラメータ** を指すものとして使います。デフォルトでは *required* です。 + +ターミナルで次のように入力するとします。 + +
+ +```bash +$ ls ./myproject + +first-steps.md intro.md +``` + +
+ +`ls` で `./myproject` ディレクトリの内容を表示します。 + +* `ls` は *プログラム*(または "command"、"CLI アプリ")です。 +* `./myproject` は *CLI 引数* で、この場合はディレクトリのパスを指しています。 + +これは、あとで出てくる **CLI option** とは少し異なります。 + +## CLI 引数を追加する + +前の例を、`name` という引数を受け取るように更新します。 + +{* docs_src/first_steps/tutorial002_py310.py hl[4,5] *} + +
+ +```console + +$ python main.py + +// 引数なしで実行すると、分かりやすいエラーが表示されます +Usage: main.py [OPTIONS] NAME +Try 'main.py --help' for help. +╭─ Error ───────────────────────────────────────────╮ + Missing argument 'NAME'. +╰───────────────────────────────────────────────────╯ + +// 次にその NAME CLI 引数を渡します +$ python main.py Camila + +Hello Camila + +// ここで "Camila" が CLI 引数です + +// 同じ CLI 引数に空白を含む名前を渡すには、引用符で囲みます +$ python main.py "Camila Gutiérrez" + +Hello Camila Gutiérrez +``` + +
+ +/// tip + +空白を含む 1 つの値を *CLI 引数* に渡す必要がある場合は、値を引用符 (`"`) で囲んでください。 + +/// + +## 2 つの CLI 引数 + +次は、名前と姓を分けて受け取りたいとします。 + +そこで、`name` と `lastname` の 2 つの引数を受け取るように拡張します。 + +{* docs_src/first_steps/tutorial003_py310.py hl[4,5] *} + +
+ +```console +// main の --help を確認します +$ python main.py --help + +Usage: main.py [OPTIONS] NAME +Try 'main.py --help' for help. +╭─ Error ───────────────────────────────────────────╮ + Missing argument 'NAME'. +╰───────────────────────────────────────────────────╯ + +typer on  richify [»!?] via 🐍 v3.7.5 (env3.7) + python main.py +Usage: main.py [OPTIONS] NAME LASTNAME +Try 'main.py --help' for help. +╭─ Error ───────────────────────────────────────────╮ + Missing argument 'NAME'. +╰───────────────────────────────────────────────────╯ + +// これで CLI 引数は 2 つ、name と lastname になりました + +// 今度は name だけを 1 つ渡してみます +$ python main.py Camila + +Usage: main.py [OPTIONS] NAME LASTNAME +Try 'main.py --help' for help. +╭─ Error ───────────────────────────────────────────╮ + Missing argument 'LASTNAME'. +╰───────────────────────────────────────────────────╯ + +// この 2 つの引数は必須なので、両方渡します +$ python main.py Camila Gutiérrez + +Hello Camila Gutiérrez +``` + +
+ +/// tip + +順番に注目してください。姓は名のあとに置く必要があります。 + +もし次のように呼び出すと: + +``` +$ python main.py Gutiérrez Camila +``` + +アプリはどちらが `name` でどちらが `lastname` かを判断できません。最初の *CLI 引数* が `name`、2 番目の *CLI 引数* が `lastname` であることを前提にしています。 + +/// + +## **CLI option** とは + +ここでは **CLI option** という言葉を、特定の名前を使って CLI アプリケーションに渡す *CLI パラメータ* を指すものとして使います。たとえば、ターミナルで次のように入力するとします。 + +
+ +```console +$ ls ./myproject --size + +12 first-steps.md 4 intro.md +``` + +
+ +`ls` は `./myproject` ディレクトリの内容を `size` 付きで表示します。 + +* `ls` は *プログラム*(または "command"、"CLI アプリ")です。 +* `./myproject` は *CLI 引数* です。 +* `--size` は省略可能な *CLI オプション* です。 + +プログラムは順序ではなく `--size` を見つけることで、サイズを表示すべきだと判断します。 + +`--size` のような *CLI オプション* は、*CLI 引数* のように順番に依存しません。 + +そのため、*CLI 引数* の *前* に `--size` を置いても動きます(実際には、それがもっとも一般的な書き方です)。 + +
+ +```console +$ ls --size ./myproject + +12 first-steps.md 4 intro.md +``` + +
+ +*CLI オプション* と *CLI 引数* の見た目上の主な違いは、*CLI オプション* には `--` が名前の前に付くことです。たとえば "`--size`" のようになります。 + +*CLI オプション* が順番に依存しないのは、事前に決まった名前を持っているからです(ここでは `--size`)。これは、CLI アプリがその特定の "name" を持つリテラルな `--size` パラメータ("flag" や "switch" とも呼ばれます)を探しているためです。CLI アプリは、あなたが入力しなかった場合でも `--size` があるかどうかを確認します。 + +一方で、CLI アプリは文字列 "`./myproject`" を持つ *CLI 引数* を積極的に探しているわけではありません。`./myproject` と入力するのか、`./my-super-awesome-project` と入力するのか、あるいはまったく別の値を入力するのかは事前に分からないからです。特定の *CLI 引数* を指していると分かる唯一の手がかりは順番です。これは、最初の *CLI 引数* が `name`、2 番目が `lastname` だと分かるのと同じです。順番を入れ替えると正しく扱えません。 + +対して、*CLI オプション* では順番は重要ではありません。 + +また、デフォルトでは *CLI オプション* は *optional*(*required* ではない)です。 + +そのため、デフォルトでは次のようになります。 + +* *CLI 引数* は **required** +* *CLI オプション* は **optional** + +ただし、*required* と *optional* のデフォルトは変更できます。 + +したがって、主な、そして **もっとも重要な** 違いは次のとおりです。 + +* *CLI オプション* は **`--` で始まり**、順番に依存しません +* *CLI 引数* は **並び順** に依存します + +/// tip + +上の例にある *CLI オプション* `--size` は、コマンドに追加されたかどうかに応じて `True` または `False` になる、単なる "flag" または "switch" です。 + +この例では値を受け取りません。しかし、*CLI オプション* も *CLI 引数* と同じように値を受け取れます。それについてはあとで見ていきます。 + +/// + +## 1 つの *CLI オプション* を追加する + +次に、`--formal` という *CLI オプション* を追加します。 + +{* docs_src/first_steps/tutorial004_py310.py hl[4,5] *} + +ここで `formal` は `bool` で、デフォルト値は `False` です。 + +
+ +```console +// help を取得します +$ python main.py --help + + Usage: main.py [OPTIONS] NAME LASTNAME + +╭─ Arguments ─────────────────────────────────────────────────────╮ +* name TEXT [default: None] [required] │ +* lastname TEXT [default: None] [required] │ +╰─────────────────────────────────────────────────────────────────╯ +╭─ Options ───────────────────────────────────────────────────────╮ +--formal --no-formal [default: no-formal] │ +--help Show this message and │ +│ exit. │ +╰─────────────────────────────────────────────────────────────────╯ +``` + +
+ +/// tip + +`formal` が `bool` であることを検出したため、自動的に `--formal` と `--no-formal` の両方が作成される点に注目してください。 + +/// diff --git a/docs/tutorial/index.ja.md b/docs/tutorial/index.ja.md new file mode 100644 index 0000000000..75b910132e --- /dev/null +++ b/docs/tutorial/index.ja.md @@ -0,0 +1,64 @@ +# 学ぶ + +この **Tutorial** - **User Guide** で、**Typer** の使い方をステップごとに学びましょう。 + +**最もシンプルなスクリプト** から **複雑な CLI アプリケーション** まで、必要なことを一通りカバーしています。 + +このドキュメントは **Typer** を学ぶための公式かつ推奨の方法だと考えてよいでしょう。 😎 + +## Python の型 + +Python の型ヒントの使い方をあらためて確認したい場合は、FastAPI の Python types intro の前半を参照してください。 + +mypy cheat sheet も確認できます。 + +要するに(本当に簡単に言うと)、次のようにパラメータ付きの関数を宣言できます。 + +```Python +from typing import Optional + +def type_example(name: str, formal: bool = False, intro: Optional[str] = None): + pass +``` + +すると、エディタは(そして **Typer** も)次のことを理解できます。 + +* `name` は `str` 型で、必須パラメータです。 +* `formal` は `bool` で、デフォルト値は `False` です。 +* `intro` は省略可能な `str` で、デフォルト値は `None` です。 + +これらの型ヒントによって、エディタでのオートコンプリートやその他の多くの機能が実現されます。 + +**Typer** は、こうした型ヒントを土台にしています。 + +## このチュートリアルについて + +このチュートリアルでは、**Typer** のすべての機能の使い方を段階的に説明します。 + +各セクションは前の内容を少しずつ積み上げていきますが、トピックは前のセクションに必ずしも依存しないので、特定の CLI の課題を解決したいときに必要な箇所へ直接進むこともできます。 + +また、あとから必要な内容を正確に見返せるように、リファレンスとしても使える構成になっています。 + +## コードを実行する + +すべてのコードブロックは、そのままコピーして使えます(テスト済みの Python ファイルです)。 + +どの例でも、コードを `main.py` というファイルにコピーして、次のように実行できます。 + +
+ +```console +$ python main.py + +✨ ここで魔法が起こります ✨ +``` + +
+ +コードは実際に自分で書くかコピーして、編集し、ローカルで動かしてみることを **強くおすすめ** します。 + +エディタで使ってみることで、どれだけ少ないコードで済むか、どのように **インラインエラー** や **オートコンプリート** などの恩恵を受けられるかが、**Typer** の本当の良さとして見えてきます。 + +そしてサンプルを実行することが、実際に何が起きているのかを **理解** するいちばんの助けになります。 + +ここにあるドキュメントをすべて読むよりも、いくつかの例を **実際に動かして** 触ってみるほうが、ずっと多くを学べます。 diff --git a/docs/tutorial/install.ja.md b/docs/tutorial/install.ja.md new file mode 100644 index 0000000000..c6238d6d2c --- /dev/null +++ b/docs/tutorial/install.ja.md @@ -0,0 +1,17 @@ +# **Typer** をインストールする + +最初のステップは **Typer** をインストールすることです。 + +まず [virtual environment](../virtual-environments.md){.internal-link target=_blank} を作成して有効化し、そのうえで次のようにインストールしてください。 + +
+ +```console +$ pip install typer +---> 100% +Successfully installed typer click shellingham rich +``` + +
+ +デフォルトでは、`typer` には `rich` と `shellingham` が含まれています。 diff --git a/docs/tutorial/printing.ja.md b/docs/tutorial/printing.ja.md new file mode 100644 index 0000000000..d10c1e57f0 --- /dev/null +++ b/docs/tutorial/printing.ja.md @@ -0,0 +1,261 @@ +# 出力と色 + +画面に情報を表示するには、通常の `print()` を使えます。 + +{* docs_src/typer_app/tutorial001_py310.py hl[8] *} + +通常どおり出力されます。 + +
+ +```console +$ python main.py World + +Hello World +``` + +
+ +## Rich を使う + +Rich を使うと、CLIをより美しく表示し、より複雑な情報も表示できます。`typer` をインストールすると、デフォルトで利用できます。 + +### Rich の `print` を使う + +もっとも単純なケースでは、`rich` から `print` をインポートして、標準の `print` の代わりに使うだけです。 + +{* docs_src/printing/tutorial001_py310.py hl[2,18] *} + +これだけで、**Rich** はデータをきれいな色と構造で出力できます。 + +
+ +```console +$ python main.py + +Here's the data +{ + 'name': 'Rick', + 'age': 42, + 'items': [ + {'name': 'Portal Gun'}, + {'name': 'Plumbus'} + ], + 'active': True, + 'affiliation': None +} +``` + +
+ +### Rich Markup + +Rich は、色やスタイルを指定するための 独自のマークアップ構文 もサポートしています。たとえば次のように使えます。 + +{* docs_src/printing/tutorial002_py310.py hl[9] *} + +
+ +```console +$ python main.py + +Alert! Portal gun shooting! 💥 +``` + +
+ +この例では、フォントスタイル、色、さらには絵文字まで使えることが分かります。 + +詳しくは Rich のドキュメント を確認してください。 + +### Rich Tables + +Rich は内部的には `Console` オブジェクトを使って情報を表示しています。 + +Rich の `print` を呼び出すと、自動的にこのオブジェクトが作成されて使われます。 + +ただし、より高度な用途では自分で `Console` を作成することもできます。 + +{* docs_src/printing/tutorial003_py310.py hl[2:3,5,12:15] *} + +この例では、`Console` と `Table` を作成し、そこにいくつかの行を追加して出力しています。 + +実行すると、きれいに整形されたテーブルが表示されます。 + +
+ +```console +$ python main.py + +┏━━━━━━━┳━━━━━━━━━━━━┓ +┃ Name Item ┃ +┡━━━━━━━╇━━━━━━━━━━━━┩ +│ Rick │ Portal Gun │ +│ Morty │ Plumbus │ +└───────┴────────────┘ +``` + +
+ +Rich には他にも多くの機能があります。たとえば次のドキュメントを確認できます。 + +* Prompt +* Markdown +* Panel +* ...and more. + +### Typer と Rich + +どの用途にどのツールを使うべきか気になるなら、**Typer** は option、argument、subcommand、データ検証などを含めてコマンドラインアプリケーションを構成するのに向いています。 + +一般に **Typer** は、利用者から最初の入力を受け取る、プログラムの入口になりやすいです。 + +**Rich** は、情報を *表示* する部分に向いています。画面に美しい内容を表示するためのものです。 + +最良のコマンドラインアプリケーションは、**Typer** と **Rich** を組み合わせることで実現できます。 + +## "Standard Output" と "Standard Error" + +出力の仕組みを内部から見ると、**オペレーティングシステム**(Linux、Windows、macOS)は、CLI プログラムが "**standard output**" という "**仮想ファイル**" に **文字列を書き込んでいる** かのように扱います。 + +コードが何かを "print" するとき、実際にはこの "standard output" という "仮想ファイル" に "書き込み" を行っています。 + +奇妙に思えるかもしれませんが、CLI プログラムとオペレーティングシステムはこのようにやり取りしています。 + +そしてオペレーティングシステムは、CLI プログラムがその "**standard output**" という "**仮想ファイル**" に "**書き込んだ**" ものを **画面に表示** します。 + +### Standard Error + +また、通常はエラー専用に使われる "**standard error**" という別の "**仮想ファイル**" もあります。 + +ただし、"standard error" にも "print" できます。そして、そのどちらもターミナル上で利用者に表示されます。 + +/// info + +PowerShell を使っている場合、"standard error" に出力した内容はターミナルに表示されないことがあります。 + +PowerShell では "standard error" を見るには変数 `$Error` を確認する必要があります。 + +ただし Bash、Zsh、Fish では通常どおり動作します。 + +/// + +### "standard error" に出力する + +Rich の `Console` を `stderr=True` で作成すると、"standard error" に出力できます。 + +/// tip + +`stderr` は "standard error" の略です。 + +/// + +`stderr=True` を使うと、出力を "standard error" に表示するよう **Rich** に伝えられます。 + +{* docs_src/printing/tutorial004_py310.py hl[4,11] *} + +ターミナルで試すと、おそらく見た目は同じです。 + +
+ +```console +$ python main.py + +Here is something written to standard error +``` + +
+ +## "Standard Input" + +最後にもう 1 つ細かい点として、ターミナルでキーボードから文字を入力するとき、オペレーティングシステムはそれも、あなたが文字列を書き込んでいる別の "**仮想ファイル**" とみなします。 + +この仮想ファイルは "**standard input**" と呼ばれます。 + +### これは何のためか + +今のところ、これはあまり役に立たないように思えるかもしれません 🤷‍♂。 + +でも、これを理解しておくと、たとえば autocompletion やテストの場面で後々役に立ちます。 + +## Typer Echo + +/// warning + +多くの場合、高度な情報を表示するには Rich を使うことをおすすめします。 + +このセクションの残りは、おそらく読み飛ばしても大丈夫です。 🎉😎 + +/// + +**Typer** にも、画面へ情報を出力するための小さなユーティリティ `typer.echo()` があります。ただし、通常はこれを使う必要はありません。 + +もっとも単純なケースでは、標準の Python `print()` を使えます。 + +そして、よりきれいにデータを表示したい場合や、より高度な内容を表示したい場合は、その代わりに **Rich** を使うべきです。 + +### なぜ `typer.echo` があるのか + +`typer.echo()`(実体はただの `click.echo()` です)は、バイナリデータを文字列に変換しようとしたり、そのほかの似た処理を行ったりするためのチェックをいくつか適用します。 + +ただし、たいていの場合はその必要はありません。現代の Python では文字列(`str`)はすでに Unicode をサポートしており、画面に表示したい純粋な `bytes` を直接扱うことはほとんどないからです。 + +もし `bytes` オブジェクトがあるなら、出力しようとする前に、意図的かつ直接 decode したくなる場合がほとんどでしょう。 + +そして、色やその他の機能付きでデータを表示したいなら、**Rich** のより高度なツールを使うほうがずっと適しています。 + +### 色 + +/// note | Technical Details + +ターミナルで色が機能する仕組みは、文字列の一部としていくつかのコード(ANSI escape sequences)を使うことです。 + +そのため、色付き文字列も依然として単なる `str` です。 + +/// + +/// tip + +繰り返しになりますが、これについても Rich を使うほうがずっと適しています。 😎 + +/// + +`typer.style()` を使うと、ターミナルに出力できる色付き文字列を作成できます。そして、その `str` を `typer.echo()` に渡せます。 + +{* docs_src/printing/tutorial005_py310.py hl[10,12] *} + +/// tip + +パラメータ `fg` と `bg` には、"foreground" と "background" の色名を表す文字列を渡します。単純に `fg="green"` や `bg="red"` を渡すこともできます。 + +ただし **Typer** は、それらを `typer.colors.GREEN` のような変数としても提供しています。色を選ぶときに autocompletion を使えるようにするためです。 + +/// + +確認してみましょう。 + +
+python main.py +everything is good +python main.py --no-good +everything is bad +
+ +`typer.style()` には次の関数引数を渡せます。 + +* `fg`: 前景色 +* `bg`: 背景色 +* `bold`: 太字表示を有効または無効にする +* `dim`: 薄い表示を有効または無効にする。これは十分にはサポートされていません +* `underline`: 下線を有効または無効にする +* `blink`: 点滅を有効または無効にする +* `reverse`: 反転表示を有効または無効にする(前景色と背景色が入れ替わります) +* `reset`: デフォルトでは、文字列の末尾に reset-all コードが追加され、スタイルが引き継がれないようになります。スタイルを組み合わせたい場合はこれを無効にできます + +### `typer.secho()` - スタイル付きで出力する + +/// tip + +上で見落としていなければ分かるとおり、これについても Rich を使うほうがずっと適しています。 😎 + +/// diff --git a/docs/tutorial/terminating.ja.md b/docs/tutorial/terminating.ja.md new file mode 100644 index 0000000000..095541b54e --- /dev/null +++ b/docs/tutorial/terminating.ja.md @@ -0,0 +1,120 @@ +# 終了する + +ある時点でコマンドを終了し、それ以降の実行をすべて止めたい場面があります。 + +コードがプログラムの正常終了を判断した場合もあれば、処理が中断された場合もあるでしょう。 + +## CLI プログラムを `Exit` する + +通常は CLI プログラムのコードを最後まで実行させれば十分ですが、シナリオによっては途中で終了したくなることがあります。そして、それ以降のコードが実行されないようにしたい場合もあります。 + +これは、必ずしもエラーを意味するわけではありません。単に、それ以上実行する必要がないだけです。 + +その場合は、`typer.Exit()` 例外を raise できます。 + +{* docs_src/terminating/tutorial001_py310.py hl[9] *} + +この例では、いくつか注目すべき点があります。 + +* CLI プログラムは他の関数ではなく `main()` 関数です。*CLI 引数* を受け取るのはこれです。 +* `maybe_create_user()` 関数は、`typer.Exit()` を raise することでプログラムを終了できます。 +* `maybe_create_user()` によってプログラムが終了した場合、`main()` 内の `send_new_user_notification()` は決して実行されません。 + +確認してみましょう。 + +
+ +```console +$ python main.py Camila + +User created: Camila +Notification sent for new user: Camila + +// 既存 user で試します +$ python main.py rick + +The user already exists + +// 通知用のコードは実行されず、2 つ目のメッセージは表示されないことに注目してください +``` + +
+ +/// tip + +例外を raise していても、それが必ずしもエラーを意味するわけではありません。 + +これは "error" のように機能して、すべての実行を止められるため例外で実現されています。 + +ただしその後 **Typer** がそれを catch し、プログラムを通常どおり終了させます。 + +/// + +## エラー付きで終了する + +`typer.Exit()` は、省略可能な `code` parameter を受け取ります。デフォルトでは `code` は `0` で、エラーがなかったことを意味します。 + +`0` 以外の数値を `code` として渡すと、プログラムの実行中にエラーがあったことをターミナルに伝えられます。 + +{* docs_src/terminating/tutorial002_py310.py hl[10] *} + +確認してみましょう。 + +
+ +```console +$ python main.py Camila + +New user created: Camila + +// 最後に実行したプログラムの終了コードを表示します +$ echo $? + +0 + +// 今度はエラー付きで終了させます +$ python main.py root + +The root user is reserved + +// 最後に実行したプログラムの終了コードを表示します +$ echo $? + +1 + +// 1 はエラーあり、0 はエラーなしを意味します。 +``` + +
+ +/// tip + +このエラーコードは、あなたの CLI プログラムを実行する別のプログラム(たとえば Bash script)から使われることがあります。 + +/// + +## Abort + +プログラムを "abort" するために使える特別な例外があります。 + +これは `typer.Exit()` とほぼ同じように動作しますが、画面に `"Aborted!"` を表示します。実行が中断されたことを明示したい場合に、あとで役立つことがあります。 + +{* docs_src/terminating/tutorial003_py310.py hl[10] *} + +確認してみましょう。 + +
+ +```console +$ python main.py Camila + +New user created: Camila + +// 今度はエラー付きで終了させます +$ python main.py root + +The root user is reserved +Aborted! +``` + +
diff --git a/docs/tutorial/typer-app.ja.md b/docs/tutorial/typer-app.ja.md new file mode 100644 index 0000000000..7782a036f4 --- /dev/null +++ b/docs/tutorial/typer-app.ja.md @@ -0,0 +1,118 @@ +# Typer App + +## 明示的なアプリケーション + +ここまでは、1 つの関数を作って、その関数を `typer.run()` に渡す方法を見てきました。 + +たとえば次のような形です。 + +{* docs_src/first_steps/tutorial002_py310.py hl[9] *} + +ただし、これは実際にはショートカットです。内部では **Typer** がそれを `typer.Typer()` を使った CLI アプリケーションに変換し、実行しています。これらはすべて `typer.run()` の中で行われています。 + +同じことを実現する、より明示的な書き方もあります。 + +{* docs_src/typer_app/tutorial001_py310.py hl[3,6,12] *} + +`typer.run()` を使うとき、**Typer** はだいたい次のようなことをしています。 + +* 新しい `typer.Typer()` の "アプリケーション" を作成する +* あなたの関数から新しい "`command`" を作成する +* その同じ "アプリケーション" を "`app()`" のように関数として呼び出す + +/// info | `@decorator` Info + +Python における `@something` という構文は "decorator" と呼ばれます。 + +関数の上に置く構文です。飾りのついた帽子のようなものだと考えてください(たぶん、そこからこの名前が来ています)。 + +"decorator" は、その下にある関数を受け取り、何らかの処理を行います。 + +ここでのデコレータは、下の関数が "`command`" であることを **Typer** に伝えています。 +コマンドについては、後ほど [commands](./commands/index.md){.internal-link target=_blank} セクションでもっと詳しく学びます。 + +/// + +`typer.run()` を使う方法も、明示的にアプリケーションを作る方法も、ほぼ同じ結果になります。 + +/// tip + +もし `typer.run()` だけで要件を満たせるなら、それで問題ありません。明示的な `app` を作って `@app.command()` などを使う必要はありません。 + +あとでアプリに追加機能が必要になったらその方法を使いたくなるかもしれませんが、まだ必要でなければそれで十分です。 + +/// + +2 番目の例、つまり明示的な `app` を使う例を実行すると、動作はまったく同じです。 + +
+ +```console +// CLI argument なし +$ python main.py + +Usage: main.py [OPTIONS] NAME +Try "main.py --help" for help. + +Error: Missing argument 'NAME'. + +// NAME CLI argument あり +$ python main.py Camila + +Hello Camila + +// help を求める +$ python main.py --help + +Usage: main.py [OPTIONS] NAME + +Options: + --install-completion Install completion for the current shell. + --show-completion Show completion for the current shell, to copy it or customize the installation. + --help Show this message and exit. +``` + +
+ +## CLI アプリケーションの補完 + +ここで注目しておく価値のある小さなポイントがあります。 + +help に 2 つの新しい *CLI オプション* が表示されるようになりました。 + +* `--install-completion` +* `--show-completion` + +shell/tab completion を使うには、自分や利用者がインストールできて、**直接呼び出せる** パッケージを作る必要があります。 + +つまり、次のように Python スクリプトを実行する代わりに: + +
+ +```console +$ python main.py + +✨ Some magic here ✨ +``` + +
+ +...次のように呼び出せるようにする、ということです。 + +
+ +```console +$ magic-app + +✨ Some magic here ✨ +``` + +
+ +そのような単体のプログラムにすることで、shell/tab completion をセットアップできるようになります。 + +インストール可能なパッケージを作成するための最初のステップは、明示的な `typer.Typer()` アプリを使うことです。 + +install 可能な単体の CLI アプリケーションを作る一連の流れについては、あとで [Build a Package](./package.md){.internal-link target=_blank} で学べます。 + +ただ、今の段階では、自分がその道の上にいると分かっていれば十分です。 😎