« ◆WF-1000Xm4とCOMPLYでノイズキャンセリング | トップページ | ◇DockerにPython常駐プログラム »

◇Pythonで例外/引数解析/Zip/Base64

 例外/引数解析/Zip/Base64

例外/引数解析/Zip/Base64のPythonでの扱いをサンプルプログラムをもちいて説明します。

4つの要素は特に関連があるものではありませんが、サンプルプログラムの都合で纏めました。

説明import型、メソッド
例外:例外表示とトレースバックtracebackException
traceback.format_exc()
コマンド引数解析argparse argparse.ArgumentParser#add_argument
argparse.ArgumentParser#parse_args
argparse.Namespace[要素]
ZIPに纏める、ZIPを展開するzipfilezipfile.ZipFile#write
zipfile.ZipFile#extractall

base64エンコード・デコード
base64 base64.encodebytes
str.encode('utf-8')
bytes(<str>, 'utf-8')
base64.decodebytes()

サンプルプログラムです。ZIPファイルを作り、Base64テキストファイル経由で別ZIPファイルに複製し、展開します。

import traceback
import argparse
import zipfile
import base64
import os
import sys

def main():
   try:
      _args_parser:argparse.ArgumentParser= argparse.ArgumentParser()
      _args_parser.add_argument("-i",required=True)       # 入力フォルダ
      _args_parser.add_argument("-iz",required=True)      # 入力のzip
      _args_parser.add_argument("-t",default="base64.txt")# base64
      _args_parser.add_argument("-oz",required=True)      # base64転送からのzip
      _args_parser.add_argument("-o",required=True)       # 出力フォルダ
      _args_parser.add_argument("-verbose",action='store_true')

      _args:argparse.Namespace =_args_parser.parse_args()

      _input_folder_name    :str =_args.i;
      _input_side_zip_mame  :str =_args.iz;
      _base64_text_file_name:str =_args.t;
      _output_side_zip_mame :str =_args.oz;
      _output_folder_name   :str =_args.o;
      V                     :bool=_args.verbose;
      #---------------------------------------------------------
      # 指定フォルダの内容をZIP化する
      #---------------------------------------------------------
      _fileNames:list[str]     = os.listdir(_input_folder_name)
      print("files="+str(_fileNames))if V else None
      _zipFile:zipfile.ZipFile = zipfile.ZipFile(_input_side_zip_mame,'w')
      for _fileName in _fileNames:
         _path:str= _input_folder_name+"/"+_fileName
         print("file="+_path) if V else None
         _zipFile.write(_path,_fileName)  # zip内に_fileの名(パス無)で書き込む
         #end-for
      _zipFile.close()

      #---------------------------------------------------------
      # binaryファイルを読み込みbase64文字列を得る
      #---------------------------------------------------------
      print("read binary "+_input_side_zip_mame)  if V else None
      _input_file_:file     = open(_input_side_zip_mame, 'rb')
      _contents_bytes:bytes = _input_file_.read()
      _input_file_.close()
      _b64bytes:bytes       = base64.encodebytes(_contents_bytes)
      _b64text:str          = _b64bytes.decode('utf-8')
      print("convert binary->base64=\n"+_b64text) if V else None
      #---------------------------------------------------------
      # base64文字列をテキストファイルに書く
      #---------------------------------------------------------
      print("write base64-text to "+_base64_text_file_name)  if V else None
      _text_file_w:file = open(_base64_text_file_name,'w')
      _text_file_w.write(_b64text)
      _text_file_w.close()

      #---------------------------------------------------------
      # base64文字列をテキストファイルから読む
      #---------------------------------------------------------
      print("read base64-text from "+_base64_text_file_name)  if V else None
      _text_file_r:file = open(_base64_text_file_name,'r')
      _o_b64text:str    = _text_file_r.read()
      _text_file_r.close()
      #---------------------------------------------------------
      # b64文字列をbinaryに変換し出力する
      #---------------------------------------------------------
      print("b64->bin and write to "+_output_side_zip_mame) if V else None
      _o_b64bytes:bytes      = bytes(_o_b64text, 'utf-8')
      _o_contents_bytes:bytes= base64.decodebytes(_o_b64bytes)
      _o_zip_file_w:file     = open(_output_side_zip_mame, 'wb')
      _o_zip_file_w.write(_o_contents_bytes) 
      _o_zip_file_w.close()

      #---------------------------------------------------------
      # ZIPファイルを展開する
      #---------------------------------------------------------
      print("expand zipFile "+_output_side_zip_mame+" to "+_output_folder_name)
      _o_zipFile_r:zipfile.ZipFile = zipfile.ZipFile(_output_side_zip_mame,'r')
      _o_zipFile_r.extractall(_output_folder_name)
      _o_zipFile_r.close()
      #end-try
   except Exception as _e:
      print("例外発生:"+str(_e)+"\n"+traceback.format_exc())
      sys.exit(1)
      #end-except
   #end-def
if __name__ == '__main__':
   main()
   #end-def

 起動引数

起動引数は次のようになっています。

   -i  名前 zipに纏めるフォルダ
   -iz 名前  zipファイル
  [-t  名前] zipファイルをbase64エンコードしたテキストファイル
             デフォルトはbase64.txt
   -oz       base64テキストから再生した出力側zipファイル
   -o        出力側zipファイルを展開するフォルダ
  [-verbose] 経過を表示

 コーディング規約

次の規約に沿って書かれています。

  • 変数導入時は必ずtype-hintをつける
    ただし、with~asの場合type-hint構文が不明のため断念する
  • 変数定義をブロックの外からは参照しない
  • ローカル変数はデバグフラグを除いて先頭にアンダースコアを付ける
    デバグフラグは大文字1文字を基本とする
  • ブロックの終わりには必ずコメントを置く
  • デバグ文の出力制御はlogerではなく、必ずローカルフラグで制御し、出力しない場合呼び出しそのものが無いようにする

ファイルは出来るだけwith~asを用いてclose()の記述を避けるようにすべきですが、ここでは型を分かりやすくするためにopen()/close()を用いています。

with~asを使いclose()を排したコードを示します。

 try~except 例外情報表示

tryを受けるexceptでは次のようにして総称Exceptionを受けます。

import traceback
###
   trace:
      #...
   except Exception as _e:
      print("例外発生:"+str(_e)+"\n"+traceback.format_exc())

traceback.format_exc()は例外の発生した場所のバックトレースが出ます。発生個所のソース名、行番号が分かります。

 コマンド引数解析

コマンド引数解析を行うは
 argparse.ArgumentParser
     _args_parser= argparse.ArgumentParser()
に、引数種分
 add_argument("引数名",...)
   _args_parser.set_arugment("-input")
を出し、
 parse_args()

 argparse.Namespace
を受け取ります。
   _args:argparse.Namespace = _args_parser.parse_arg()
argparse.Namespaceは辞書のようなもので、引数名の要素を持ち、例えば引数として"-input"を指定してあれば, -を除いた名前
 .input
で値を得ることができます。
   _in:str= _args.input;

set_arugment()で指定するのはパラメタ名の他型、デフォルト値、などの設定ができます。

   _args_parser.set_arugment("-n",type:int)      # int型
   _args_parser.set_arugment("-a",default:"abc") # 無指定時の値
   _args_parser.set_arugment("-b",required=True) # 省略不能
   #
   _args:argparse.Namespace = _args_parser.parse_arg()
   _n:int = _args.n # int値が得られる
   _a:str = _args.a # 省略値は"abc"  defaultを指定せず省略した場合はNone
   _b:str = _args.b # 省略時はparse_arg()で例外が発生

付帯引数のない指定でbool値となるものは別の指定法('action'=指定)を採ります。

   _args_parser.add_argument("-verbose",action='store_true')
   # 
   _args:argparse.Namespace = _args_parser.parse_arg()
   _v:int = _args.verbose

action='store_true'は指定があるとTrue、即ちデフォルト値がFalse,
action='store_false'は指定があるとFalse、即ちデフォルト値がTrueとなります。

-h/--helpによるパラメタ表示がデフォルトで生成されます。

-を付けないパラメタは位置指定となります。絶対に行ってはなりません。

 Zip

ZIPファイル作成は
 zipfile.ZipFile(名前,"w")
でオープンし、
 write(書き込むファイルのパス、zipファイル内に設定する名前)
を必要回繰り返します。

ZIPの展開は
 zipfile.ZipFile(名前,"r")
でオープンし、
 extractall(出力フォルダ名)
で一気に展開する形となります。

 Base64

base64の取り扱いは
 base64.encodebytes(
 base64.decodebytes(
で行います。

注意しなくてはならないのが、本来base64データはテキストであるにもかかわらず、インターフェース上bytesを用いるという、全くもって意味不明の仕様となっているところです、

base64へのエンコードは次のように行います。
 _binary_data:bytes = バイナリデータ
 _b64_bytes:bytes = base64.encodebytes(_binary_data)
 _b64_text:str = _b64_bytes.decode('utf-8')

base64からバイナリデータへのデコードは次のように行います。
 _b64_text:str = base64テキスト
 _b64_bytes:bytes = bytes(_b64_text,'utf-8')
 _binary_data:bytes = base64.decodebytes(_b64_bytes)

 サンプルダウンロード

次の場所からサンプルがダウンロードできます。

zipandbase64.zip

次の内容となっています。

   test_dir       :  zipする試験データフォルダ
   A00_clean.bat  : 二次ファイルの削除
   A05_test.bat   : ビルドして試験を実施する
   A06_test.bat   : with-as版をビルドして試験を実施する
   base64test.py  : 試験プログラム
   base64testw.py : with-as版試験プログラム

A05_test.batでは次のパラメタで試験プログラムが起動されます。

set OPTIONS=-i test_dir -iz _test_dir.zip -t _test_base64.txt ^
                        -oz _test_out.zip -o _test_out -verbose
python base64test.py %OPTIONS%

試験を実施すると以下のファイル・フォルダが作成されます。

  _test_dir.zip     zipファイル
  _test_base64.txt  zipファイルをbase64テキストにしたもの
  _test_out.zip     base64テキストから作られたzip
  _test_out         _test_out.zipを展開したフォルダ

これらの二次ファイルはA00_clean.batで消去できます。

|

« ◆WF-1000Xm4とCOMPLYでノイズキャンセリング | トップページ | ◇DockerにPython常駐プログラム »