Help us understand the problem. What is going on with this article?

PythonによるCLIの作成(その2)

More than 1 year has passed since last update.

はじめに

この記事は前回の記事の内容の実装編になります
CLIって何?とかargparseって何?ってなったらそちらを参照するか調べるかして頂ければと思います
実装の内容もありふれているものばかりなので備忘録(常套句)と思って頂ければ幸いです
※ちなみにコードは前回にも掲載しましたが、CLIへのリンクではないためこちらに改めて貼っておきます。ただしそのうちmasterブランチに統合するため統合され次第この部分は削除します

DB作成

やったことリストとして様々なタスクを保存する必要があります
最初はshelveを使って本当に簡単なものを作成しましたが、セキュリティ面と同じ手軽さを合わせて考慮してsqlite3を用いることにします
Pythonにおいて、sqlite3によるDBの設計は非常に簡単で下記のテーブルを作成する際

$ sqlite3
sqlite>.read create.sql 
create.sql
create table tasks
(
    id integer primary key,
    tag_id integer,
    name text,
    content text,
    tag text,
    done_date timestamp
);

とすれば完成します

構成

具体的な構成として、以下のようにコードを分けていきます

task.py     ...  タスクの処理
command.py  ...  オプションに対する操作の振り分け
todone.py   ...  メイン

メイン

前回で述べたように、argparseを用いて様々な操作を受け付けるようにします
それぞれの操作についてはgithubの方に記載しています
DBへの接続はconnectメソッドによって行い、コマンドラインの引数を解釈するparse_args()メソッドにDBの設定を追加します

todone.py
#!/usr/local/Cellar/python3/3.5.1/bin/python3.5
import argparse
import sqlite3
from command import Command

db_name = "d_todone.db"


def main():
    parser = argparse.ArgumentParser()
    subparsers = parser.add_subparsers()
    add_parser = subparsers.add_parser('add')
    add_parser.set_defaults(func=Command.cmd_add)
    list_parser = subparsers.add_parser('list')
    list_parser.add_argument('-t', '--tag')                        default="task_id")
    list_parser.set_defaults(func=Command.cmd_list)
    content_parser = subparsers.add_parser('content')
    content_parser.add_argument('-c', '--change', action="store_true")
    content_parser.add_argument('-d', '--delete', action="store_true")
    content_parser.set_defaults(func=Command.cmd_content)
    args = parser.parse_args()
    args.db = sqlite3.connect(db_name)
    if hasattr(args, 'func'):
        args.func(args)
    else:
        parser.print_help()

if __name__ == '__main__':
    main()

このとき、スクリプトファイルを実行可能にするためにファイル自体に実行権限を追加していきます

$ chmod +x todone.py

なおかつ、todone.pyの1行目に

todone.py
#!/usr/local/Cellar/python3/3.5.1/bin/python3.5

とpythonを実行する場所を宣言します(これは各自違うので各々確認してください)
こうすることで以下のように実行可能です

$ todone.py

操作の振り分け

todone.pyにおいて
・ タスクの追加をCommand.cmd_add
・ タスクの一覧表示をCommand.cmd_list
・ タスクの内容表示をCommand.cmd_content
と振り分けています
また、parserで得られた引数によってそれぞれの関数内で処理を変えます

command.py
from datetime import datetime
from task import Task


class Command:
    def cmd_add(args):
        name = input('task name:')
        content = input('task content:')
        tag = input('task\'s tag:')
        done_date = datetime.strptime(input('done date [Y-m]:'), '%Y-%m')
        Task.create_task(name, content, tag, done_date, args.db)

    def cmd_list(args):
        if args.tag is None:
            Task.all_task(args.db)
        else:
            Task.tag_task(args.db, args.tag)

    def cmd_content(args):
        task_name = input('task_name:')
        if args.delete:
            Task.delete_task(args.db, task_name)
            print("Delete task:{0}", task_name)
        else:
            Task.part_task(args.db, task_name)
            if args.change:
                content = input('content:')
                Task.update_task(args.db, task_name, content)
                Task.part_task(args.db, task_name)

タスクの処理

主なDB処理をここで行っていきます
db.commit()としてDBに保存する処理を必ず加えることを念頭にいれておきます(備忘録, with使えばいいってお話でもある)

task.py
class Task:

    def create_task(name, content, tag, done_date, db):
        cur = db.cursor()
        c_sql = 'select count(*) from tasks where tag = ?'
        sql = 'insert into tasks (tag_id, name, content, tag, done_date) values (?, ?, ?, ?, ?)'
        tag_id = int(str(cur.execute(c_sql, [tag]).fetchone()[0]))
        task = (tag_id, name, content, tag, done_date)
        cur.execute(sql, task)
        db.commit()
        db.close()

    def update_task(db, name, content):
        sql = 'update tasks set content = ? where name = ?'
        update = [content, name]
        db.execute(sql, update)
        db.commit()
        db.close()

    def delete_task(db, name):
        cur = db.cursor()
        sql = 'delete from tasks where name = ?'
        cur.execute(sql, [name])
        db.commit()
        db.close()

    def all_task(db):
        cur = db.cursor()
        sql = 'select * from tasks'
        for row in cur.execute(sql):
            print(row[4])
        db.close()

    def part_task(db, task_name):
        sql = 'select * from tasks where name=?'
        for key in db.execute(sql, task_name):
            print("tag: {row[4]}\n name: {row[2]}\n content: {row[3]}\n done_date: {row[5]}")

    def tag_task(db, tag):
        sql = 'select * from tasks where tag=?'
        for row in db.execute(sql, tag):
            print("{row[4]}...{row[2]} <date>:{row[5]}")

まとめ

ご覧の通り非常に簡単にCLIを構築できることがわかります(もちろん様々な事を考慮するとまだまだの出来とも言えますが)
実装自体は簡単でしたが、忘れてしまわないようにするためにも今回作成しました
ご指摘等あればよろしくお願いいたします

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした