動機
python
の標準ライブラリにふくまれるコマンドライン・パーサーargparseでは、引数の型としてファイルオブジェクトを指定することができる。(argparse.FileType
) 文字列からわざわざファイルオブジェクトを生成したりする必要がないので大変便利である。
しかし、書き込みモード(mode='w'
)を指定した場合でも有無を言わさず自動的に開いてしまうので、おっちょこちょいな人にとっては、意図せずにファイルを上書きして内容を消してしまう恐れがあり、大変危険である。そこで、ファイルの上書き確認を実装したので、やり方をわすれないようにメモしておく。
実装例。
文末に挙げたサイトのやり方を参考にして拙作pdf_merge_multipagesに実装した例。
pdf_merge_multipages.py(抜粋)
class FileTypeWithCheck(argparse.FileType):
def __call__(self, string):
if string and "w" in self._mode:
if os.path.exists(string):
sys.stderr.write(('File: "%s" exists. Is it OK to overwrite? [y/n] : ') % (string))
ans = sys.stdin.readline().rstrip()
ypttrn = re.compile(r'^y(es)?$', re.I)
m = ypttrn.match(ans)
if not m:
sys.stderr.write("Stop file overwriting.\n")
sys.exit(1)
# raise ValueError('Stop file overwriting')
if os.path.dirname(string):
os.makedirs(os.path.dirname(string),
exist_ok=True)
return super(FileTypeWithCheck, self).__call__(string)
def __repr__(self):
return super(FileTypeWithCheck, self).__repr__()
....
....
def main():
argpsr = argparse.ArgumentParser(description='Merge multiple mages in PDF files w/o gap.')
argpsr.add_argument('inputs', metavar='input-file', type=argparse.FileType('rb'),
nargs='+', help='Input PDF file(s)')
argpsr.add_argument('-output', metavar='filename', type=FileTypeWithCheck('wb'),
nargs=1, help='Output file', dest='output', default='a.out.pdf')
...
...
def main():
argpsr = argparse.ArgumentParser(description='Merge multiple mages in PDF files w/o gap.')
argpsr.add_argument('inputs', metavar='input-file', type=argparse.FileType('rb'),
nargs='+', help='Input PDF file(s)')
argpsr.add_argument('-output', metavar='filename', type=FileTypeWithCheck('wb'),
nargs=1, help='Output file', dest='output', default='a.out.pdf')
...
...
if __name__ == '__main__':
main()
ファイルが存在していて上書きを回避したときに、そこでスクリプトを終了(exit()
)するかもしくは例外を送出するかは、場合によって選択が必要であろう。上記の例ではexit()
しているが、先にinputs
の引数で読み込みモードでファイルが開かれていた場合に、それを閉じる処理をせずにスクリプトが終了することになる可能性が残るところがちょっと引っかかる点ではある。