MAGAZINE

ルーターマガジン

Python

[CSV]Pythonで作る自作CLI(コマンドラインツール)

2022.01.07
Pocket

はじめに

こんにちは、学生バイトの福島です。私がルーターに来てからはや一年半ほどが経ち、この記事でブログも3回目となります。

過去記事↓

pythonでlineへ通知してみよう!

前回に続き今回もpythonを使って、csvの指定したカラムで重複を除いたものを出力するコマンドラインツールを作成してみようと思います。

Excelでいいのでは?

Excelを使えば同様のことが普通にできますが(もちろんスプレッドシートでも)、割と面倒ですし、いつでもExcelを使える環境とは限りません。

コマンドラインツール化してしまえば一行で完結しますし、シェルスクリプトに組み込めばできることがかなり広がります

なんでPython?

最近話題のrustでコマンドラインツールを書いてみたかったのですが、初見すぎたので前章として今回はpythonで書き、次回rustで書き直したいと思います。

  • 標準でOSにインストールされていることが多い
  • パッケージ化が楽
  • 個人的に好き

成果物のイメージ

pycsvという名前にします。コマンドの引数に対象ファイル名とカラム名を渡すと、重複を除外したcsv形式の文字列を標準出力に吐き出します。コマンドのイメージは以下。

$ pycsv files/sample.csv column_name > uniqued.csv

オプションで重複行のみを出力もできるようにしてみようと思います

着手

ディレクトリ構成

作業ディレクトリ内に具体的な処理を記述するmain.pyとツール関連の記述をするsetup.pyを用意します

    
        .
        ├── main.py  
        └── setup.py
    

main.py

-dupまたは--duplicateをオプションで渡すと重複した行のみ出力するようにしました

    
        import argparse
        import csv
        
        def main():
            args = config_args()
            target_column = args.column
            with open(args.file_path) as f:
                reader = csv.reader(f)
                rows = list(reader)
            header = rows.pop(0)
            # 重複判定対象のカラムのindexを取得
            target_index = header.index(target_column)
            # コマンドライン引数よりモード判定
            show_duplicate_flg = args.duplicate
            parsed_rows = parse_rows(rows, target_index, show_duplicate_flg)
            if show_duplicate_flg == True and len(parsed_rows) == 0:
                # 重複がない時
                print('nothing duplicated !🍷')
            else:
                print(','.join(header))
                for row in parsed_rows:
                print(','.join(row))
            return
        
        
        # コマンドライン引数設定
        def config_args():
            arg_parser = argparse.ArgumentParser()
            arg_parser.add_argument('file_path', help='file path of target csv')
            arg_parser.add_argument('column', help='target column name')
            arg_parser.add_argument('-dup', '--duplicate', 
                                      help='show duplicated_rows', action='store_true')
            args = arg_parser.parse_args()
            return args
        
        
        def parse_rows(rows, target_index, show_duplicate):
            exist_columns = []
            column_append = exist_columns.append
            result_rows = []
            row_append = result_rows.append
            for row in rows:
                column = row[target_index]
                if column not in exist_columns:
                    column_append(column)
                    if show_duplicate == False: row_append(row)
                else:
                    if show_duplicate == True: row_append(row)
            return result_rows
        
        
        if __name__ == '__main__':
            main()
    

setup.py

requestsやpandasなどの外部ライブラリを利用する場合は

install_requires = ['requests', 'pandas']

のように書きます。今回は外部ライブラリを利用していないので空リストになっています。

    
        # setup.py
        from setuptools import setup
        
        setup(
            name = 'pycsv', # ツール名
            version = '1.0.0',
            install_requires = [],
            entry_points = {
                "console_scripts": ['pycsv = main:main'], # ['ツール名 = ファイル名:関数名']
            }
        )
    

main.pyとsetup.pyの2ファイルが用意出来たらパッケージ化します。作業ディレクトリ内で

$ pip install --editable .

を実行するとファイルが生成され、install完了です。

    
        .
        ├── __pycache__
        │   └── main.cpython-39.pyc
        ├── pycsv.egg-info
        │   ├── PKG-INFO
        │   ├── SOURCES.txt
        │   ├── dependency_links.txt
        │   ├── entry_points.txt
        │   └── top_level.txt
        ├── main.py
        └── setup.py
    

pathもちゃんと通ってますね

    
        $ which pycsv
        /home/ubuntu/.pyenv/shims/pycsv
    

動作確認

動作確認をしてみましょう。単体テストの実装はまた別の機会に。

test.csvとしてCSVファイルを用意します。

    
        id,name
        1,東京
        2,千葉
        3,東京
        4,神奈川
    

nameカラムの"東京"が重複していますね。どちらかだけにしたいのでnameカラムに対してコマンドを使ってみます。

    
        $ pycsv test.csv name
        id,name
        1,東京
        2,千葉
        4,神奈川
    

idが3の東京が除外されました。期待通りです。

次は -dupオプションをつけて重複行だけを出力してみます

    
        $ pycsv test.csv name -dup
        id,name
        3,東京
    

まとめ

setup_toolsを使うことでかなり簡単に自作ツールができました。次回はrustで同じものを作り、次々回でpythonとrustの比較をしてみようと思います。

rust編につづく

参考

setuptools公式
Pocket

CONTACT

お問い合わせ・ご依頼はこちらから