自分でちょっとずつ作っている cuekoma(python) は、年に数回しか使わない。 たぶん、そんな理由で、今年の秋のツーリング準備で使おうとしたら、使い方を忘れていた。 健忘症なのか痴呆症なのか。
コードを読んだりしてる時間が結構無駄。 なので、少しメニュー化することを真剣に考えようと思った次第。
が、今回は間に合うわけもないので、雛形だけ作ってみた。 省メモリ、省codeにしたいので、いわゆる、GUI のメニューでは無い。 しかも、ダイアログなんかも使わないシンプルなやつ。
やりたい事は、
- スクリプトを走らせると、
- 簡単な概要を表示して(configparserではない)、
- ジョブを選択して、
- 必要な設定ファイルを選択して、
- 実行する。
という、単純なもの。なにげに、 MS-DOS を思い起させるヤツだ。
使ったのは、 python-prompt-toolkit で、html のような設定で色付けとか、太字とかも可能。そして、logzero と使い分けることも。
現状は以下。
稚拙な source が下。
#!~/.pyenv/shims/python
"""Viking data file handling tool."""
from __future__ import unicode_literals
import os
import sys
import logging
from pathlib import Path
import logzero
from fuzzyfinder import fuzzyfinder
from prompt_toolkit import HTML, prompt
from prompt_toolkit import print_formatted_text as pprint
from prompt_toolkit.history import FileHistory
from prompt_toolkit.completion import Completer, Completion, WordCompleter
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
from prompt_toolkit.formatted_text import FormattedText
# script run path
os.chdir(Path("~/Documents/proj/gpxs").expanduser())
# the Python 3.6 or above, os.chdir() can deal with Path object directly.
LOG_FORMAT = "%(color)s[%(module)s:%(lineno)3d]%(end_color)s %(message)s"
FORMATTER = logzero.LogFormatter(fmt=LOG_FORMAT)
logzero.setup_default_logger(formatter=FORMATTER)
logzero.logfile("./_logs/pp-menu.log", maxBytes=3e5, backupCount=3)
logzero.loglevel(logging.DEBUG)
def get_keypars(key_par, in_buf, key_nam):
"""Parse key parameters of this application."""
if in_buf[0] != "#" and in_buf[0] != "\n":
if in_buf[0] in ["["]:
key_nam = in_buf.split("[")[1].split("]")[0]
if key_nam not in key_par.values():
key_par[key_nam] = {"cate": key_nam}
else:
key_par[key_nam][in_buf.split("=")[0].strip()] = in_buf.split("=")[
1
].strip()
return key_par, key_nam
def read_ppmenu_ini(ini_f):
"""Read script setting ini file."""
with open(ini_f, "r") as in_file:
key_par, key_nam = {}, ""
for in_buf in in_file:
key_par, key_nam = get_keypars(key_par, in_buf, key_nam)
return key_par
def show_app_para(app_parm):
"""Show script parameters and description."""
_str = "run dir : %s " % str(Path.cwd().relative_to(Path.home()))
pprint(HTML(' - <skyblue>%s</skyblue> (application\'s ini file is hear)' % _str))
tour_path = Path(app_parm["app"]['top_dir'])
_str = "data dir : %s " % str(tour_path.relative_to(Path.home()))
pprint(HTML(' - <skyblue>%s</skyblue> (user\'s data(in/out) directory.)' % _str))
_str = "co_poi.vik : 個人的なPOIを収めている viking のデータファイル."
pprint(HTML('\n - <skyblue>%s</skyblue>' % _str))
_str = "\n 簡単な説明を付け加えておく方が良いと、後悔している。\n"
pprint(HTML(' <skyblue>%s</skyblue>' % _str))
class MyfileCompleter(Completer):
"""Set Completer."""
def __init__(self, globbed_path):
self.globbed_path = globbed_path
self.inifile_list = [f.name for f in self.globbed_path.glob("*.ini")]
self.num_setfile = len(self.inifile_list)
def get_completions(self, document, complete_event):
"""Set Completer."""
word_before_cursor = document.get_word_before_cursor(WORD=True)
matches = fuzzyfinder(word_before_cursor, self.inifile_list)
for m in matches:
yield Completion(m, start_position=-len(word_before_cursor))
def select_ini_file(globbed_path):
"""Select tour ini file."""
_s_text = FormattedText([
('#cccccc bold', "- Select ini file. "),
('#9999cc', '( %d ini files in dir.)\n' % MyfileCompleter(globbed_path).num_setfile),
('#7766cc', " (<tab>key show list)\n > "),
])
user_input = prompt(
_s_text,
history=FileHistory('pp-menu-ini-history.txt'),
auto_suggest=AutoSuggestFromHistory(),
completer=MyfileCompleter(globbed_path),
)
_s_text = FormattedText([
('#d15fee italic', ' >> INI file : '),
('#e066ff', user_input),
('#d15fee italic', '.\n'),
])
pprint(_s_text)
return Path(globbed_path / user_input)
def select_job_category():
"""Select job."""
job_list = [
"10: co-poi.vik (change waypoint symbol to default)",
"11: co-poi.vik (re-build from vildata. require co_poi_lay.set)",
"12: co-poi.vik (copy to custom POI dir. require to_garmin_poi.set) ",
"13: conv. to vildata, from all gpx data(check ...)",
"14: conv. to vildata, from all json data(check ...)",
"99: quit",
]
job_index = [int(x.split(':')[0]) for x in job_list]
_job_list_text = '\n ' + '\n '.join(job_list) + ''
_s_text = FormattedText([
('#cccccc bold', '- Select job : \n'),
('#7799dd', _job_list_text),
('#7766cc', "\n\n <tab>key select from list."),
(' ', '\n\n > '),
])
job_completer = WordCompleter(job_list, ignore_case=True, )
user_input = prompt(
_s_text,
history=FileHistory("pp-menu-job-history.txt"),
completer=job_completer
)
_s_text = FormattedText([
('#d15fee italic', ' >> JOB: '),
('#e066ff', user_input),
('#d15fee italic', '.\n'),
])
pprint(_s_text)
job_number = user_input.split(':')[0]
if int(job_number) not in job_index:
# while でループへ。
logzero.logger.info("!! select wrong job !!")
sys.exit()
if int(job_number) == 99:
pprint(HTML('\n<b> * ばいばい *</b>\n'))
sys.exit()
return job_number
def main():
"""Read config and set and select select job."""
pprint(HTML('\n<b><i>* menu test using python prompt toolkit .............</i></b>\n'))
# スクリプトの共通パラメタの読み込み
ppmenu_ini_file = Path.cwd() / "pp-menu.ini"
app_parm = read_ppmenu_ini(ppmenu_ini_file)
show_app_para(app_parm)
# ジョブの選択
job_number = select_job_category()
# 個別設定ファイルの選択
globbed_path = Path(app_parm['app']['top_dir'])
tour_setfile = select_ini_file(globbed_path)
logzero.logger.info(tour_setfile)
logzero.logger.info(job_number)
if __name__ == "__main__":
main()
sys.exit()
年末にかけて、ちょっとづつ進めようと思っている。 メニュー化で整理しようとすると、色々、`あれ` という事が噴出してるから。




