MAGAZINE
ルーターマガジン
[CSV]Pythonで作る自作CLI(コマンドラインツール)
はじめに
こんにちは、学生バイトの福島です。私がルーターに来てからはや一年半ほどが経ち、この記事でブログも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公式CONTACT
お問い合わせ・ご依頼はこちらから