コンテンツにスキップ

ファイル

Path CLIパラメータに加えて、いくつかの種類の「ファイル」を宣言することもできます。

ヒント

ほとんどの場合、Path を使用すれば問題ありません。

Path を使用して、同じ方法でデータを読み書きできます。

違いは、これらの型はPythonのファイルライクオブジェクトを、PythonのPathの代わりに提供することです。

「ファイルライクオブジェクト」とは、以下のようにopen() によって返されるのと同じタイプのオブジェクトです。

with open('file.txt') as f:
    # Here f is the file-like object
    read_data = f.read()
    print(read_data)

ただし、特別なユースケースでは、これらの特別な型を使用する必要がある場合があります。たとえば、既存のアプリケーションを移行する場合などです。

FileText 読み込み

typer.FileText は、テキストを読み込むためのファイルライクオブジェクトを提供します。そこから str データを取得します。

これは、ファイルに英語以外の言語で書かれたテキストが含まれている場合でも、たとえば、text.txt ファイルに次のような内容が含まれている場合でも、

la cigüeña trae al niño

たとえば、次のようなテキストを含む str があります。

content = "la cigüeña trae al niño"

bytes を持つ代わりに、たとえば、

content = b"la cig\xc3\xbce\xc3\xb1a trae al ni\xc3\xb1o"

ファイルライクオブジェクトのすべての正しいエディターサポート、属性、メソッドなどが得られます。

import typer
from typing_extensions import Annotated


def main(config: Annotated[typer.FileText, typer.Option()]):
    for line in config:
        print(f"Config line: {line}")


if __name__ == "__main__":
    typer.run(main)

ヒント

可能な場合は、Annotated バージョンを使用することをお勧めします。

import typer


def main(config: typer.FileText = typer.Option(...)):
    for line in config:
        print(f"Config line: {line}")


if __name__ == "__main__":
    typer.run(main)

確認してください

// Create a quick text config
$ echo "some settings" > config.txt

// Add another line to the config to test it
$ echo "some more settings" >> config.txt

// Now run your program
$ python main.py --config config.txt

Config line: some settings

Config line: some more settings

FileTextWrite

テキストを書き込むには、typer.FileTextWrite を使用できます。

import typer
from typing_extensions import Annotated


def main(config: Annotated[typer.FileTextWrite, typer.Option()]):
    config.write("Some config written by the app")
    print("Config written")


if __name__ == "__main__":
    typer.run(main)

ヒント

可能な場合は、Annotated バージョンを使用することをお勧めします。

import typer


def main(config: typer.FileTextWrite = typer.Option(...)):
    config.write("Some config written by the app")
    print("Config written")


if __name__ == "__main__":
    typer.run(main)

これは、次のような人間のテキストを書き込むためのものです。

some settings
la cigüeña trae al niño

...バイナリ bytes を書き込むためではありません。

確認してください

$ python main.py --config text.txt

Config written

// Check the contents of the file
$ cat text.txt

Some config written by the app

技術的な詳細

typer.FileTextWrite は単なる便利なクラスです。

これは、typer.FileText を使用して mode="w" を設定するのと同じです。 mode については、以下で詳しく説明します。

FileBinaryRead

バイナリデータを読み込むには、typer.FileBinaryRead を使用できます。

そこから bytes を受け取ります。

画像のようなバイナリファイルを読み込むのに便利です。

import typer
from typing_extensions import Annotated


def main(file: Annotated[typer.FileBinaryRead, typer.Option()]):
    processed_total = 0
    for bytes_chunk in file:
        # Process the bytes in bytes_chunk
        processed_total += len(bytes_chunk)
        print(f"Processed bytes total: {processed_total}")


if __name__ == "__main__":
    typer.run(main)

ヒント

可能な場合は、Annotated バージョンを使用することをお勧めします。

import typer


def main(file: typer.FileBinaryRead = typer.Option(...)):
    processed_total = 0
    for bytes_chunk in file:
        # Process the bytes in bytes_chunk
        processed_total += len(bytes_chunk)
        print(f"Processed bytes total: {processed_total}")


if __name__ == "__main__":
    typer.run(main)

確認してください

$ python main.py --file lena.jpg

Processed bytes total: 512
Processed bytes total: 1024
Processed bytes total: 1536
Processed bytes total: 2048

FileBinaryWrite

バイナリデータを書き込むには、typer.FileBinaryWrite を使用できます。

それに bytes を書き込みます。

画像のようなバイナリファイルを書き込むのに便利です。

.write() メソッドには、str ではなく bytes を渡す必要があることに注意してください。

str がある場合は、最初にエンコードして bytes を取得する必要があります。

import typer
from typing_extensions import Annotated


def main(file: Annotated[typer.FileBinaryWrite, typer.Option()]):
    first_line_str = "some settings\n"
    # You cannot write str directly to a binary file, you have to encode it to get bytes
    first_line_bytes = first_line_str.encode("utf-8")
    # Then you can write the bytes
    file.write(first_line_bytes)
    # This is already bytes, it starts with b"
    second_line = b"la cig\xc3\xbce\xc3\xb1a trae al ni\xc3\xb1o"
    file.write(second_line)
    print("Binary file written")


if __name__ == "__main__":
    typer.run(main)

ヒント

可能な場合は、Annotated バージョンを使用することをお勧めします。

import typer


def main(file: typer.FileBinaryWrite = typer.Option(...)):
    first_line_str = "some settings\n"
    # You cannot write str directly to a binary file, you have to encode it to get bytes
    first_line_bytes = first_line_str.encode("utf-8")
    # Then you can write the bytes
    file.write(first_line_bytes)
    # This is already bytes, it starts with b"
    second_line = b"la cig\xc3\xbce\xc3\xb1a trae al ni\xc3\xb1o"
    file.write(second_line)
    print("Binary file written")


if __name__ == "__main__":
    typer.run(main)
$ python main.py --file binary.dat

Binary file written

// Check the binary file was created
$ ls ./binary.dat

./binary.dat

ファイル CLIパラメータ 設定

typer.Option() および typer.Argument() で、これらの型(クラス)にいくつかの設定パラメータを使用できます。

  • mode: ファイルを開く「モード」を制御します。
    • 上記のクラスを使用することで自動的に設定されます。
    • 詳細については、以下をお読みください。
  • encoding: 特定のエンコーディング(例:"utf-8")を強制します。
  • lazy: I/O 操作を遅延させます。デフォルトでは自動です。
    • デフォルトでは、ファイルを書き込むとき、Click はまだ実際のファイルではないファイルライクオブジェクトを生成します。書き込みを開始すると、ファイルが開かれ、書き込みが開始されますが、それまでは開始されません。これは、主に書き込みを開始するまでファイルの作成を回避するのに役立ちます。通常は、これを自動のままにしておく方が安全です。ただし、lazy=False を設定することで上書きできます。デフォルトでは、書き込みの場合は lazy=True、読み込みの場合は lazy=False です。
  • atomic: true の場合、すべての書き込みは実際には一時ファイルに行われ、完了後に最終的な宛先に移動されます。これは、複数のユーザー/プログラムによって頻繁に変更されるファイルで役立ちます。

高度な mode

デフォルトでは、Typermode を自動的に設定します。

  • typer.FileText: mode="r"、テキストを読み込みます。
  • typer.FileTextWrite: mode="w"、テキストを書き込みます。
  • typer.FileBinaryRead: mode="rb"、バイナリデータを読み込みます。
  • typer.FileBinaryWrite: mode="wb"、バイナリデータを書き込みます。

FileTextWrite についての注意

typer.FileTextWrite は実際には単なる便利なクラスです。 typer.FileTextmode="w" を使用するのと同じです。

ただし、他のクラスと同様に、エディターで typer.File... と入力するだけで自動補完で取得できるため、おそらく短く、より直感的です。

mode のカスタマイズ

上記のデフォルトから mode をオーバーライドできます。

たとえば、mode="a" を使用して、同じファイルに「追加」書き込みを行うことができます。

import typer
from typing_extensions import Annotated


def main(config: Annotated[typer.FileText, typer.Option(mode="a")]):
    config.write("This is a single line\n")
    print("Config line written")


if __name__ == "__main__":
    typer.run(main)

ヒント

可能な場合は、Annotated バージョンを使用することをお勧めします。

import typer


def main(config: typer.FileText = typer.Option(..., mode="a")):
    config.write("This is a single line\n")
    print("Config line written")


if __name__ == "__main__":
    typer.run(main)

ヒント

mode="a" を手動で設定しているので、typer.FileText または typer.FileTextWrite を使用できます。どちらも機能します。

確認してください

$ python main.py --config config.txt

Config line written

// Run your program a couple more times to see how it appends instead of overwriting
$ python main.py --config config.txt

Config line written

$ python main.py --config config.txt

Config line written

// Check the contents of the file, it should have each of the 3 lines appended
$ cat config.txt

This is a single line
This is a single line
This is a single line

異なる型について

情報

これらは、Typer によって提供される異なる型/クラスの理由に関する技術的な詳細です。

ただし、これらを使用するためにこの情報は必要ありません。スキップできます。

Typer は、これらの異なる型(クラス)を提供します。なぜなら、それらは各ケースで下に提供される実際の Python 実装を直接継承しているからです。

これにより、エディターは各型に対して正しい型チェックと補完を提供します。

lazy を使用する場合でも。 lazy を使用すると、Click は書き込みを遅延させるための特別なオブジェクトを作成し、書き込まれる実際のファイルへの「プロキシ」として機能します。ただし、この特別なプロキシオブジェクトは、エディターでの型チェックと補完に必要な属性とメソッドを公開しません。これらの属性にアクセスしたり、メソッドを呼び出すと、「プロキシ」lazy オブジェクトは最終オブジェクトでそれらを呼び出し、すべてが機能します。ただし、それらに対する自動補完は得られません。

ただし、これらの **Typer** クラスは、下に提供される実際の実装(lazy オブジェクトではない)を継承しているため、エディターですべての自動補完と型チェックが得られます。