my-psb/openclassrooms-trainings/pytestdiscovering/cli.py

302 lines
8.6 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Author: freezed <freezed@users.noreply.github.com> 2018-08-04
Version: 0.1
Licence: `GNU GPL v3` GNU GPL v3: http://www.gnu.org/licenses/
Command line interface to interact with local DB
Choose a product in a list of aivaiable categories['results_list'],
the system gives you an alternative with a better 'nutriscore'.
You can save this product to get it later.
"""
from os import system
from db import Db
from config import DB_REQUEST, CLI_MSG_DISCLAIMER, CLI_MSG_ASK_IDX, \
CLI_MSG_ASK_ERR, CLI_MSG_QUIT, CLI_MSG_CHOOSEN_CAT, CLI_MSG_PROD, \
CLI_MSG_SUBST, CLI_MSG_NO_SUBST, CLI_MSG_CAT, CLI_MSG_CHOOSEN_PROD, \
CLI_MSG_DETAILLED_SUB, CLI_MAX_LEN, \
CLI_ITEM_LIST, CLI_MSG_ASK_BAK, CLI_MSG_BAK_DONE, CLI_MSG_INIT_MENU,\
CLI_MSG_SUBST_HEAD, CLI_MSG_SUBST_TITLE, CLI_MSG_SUBST_LIST
product_asked = {'valid_item': False}
cli_end_msg = CLI_MSG_QUIT
def ask_user(head_msg, item_list):
"""
Ask user to choose an item in the provided list, using numeric index
:head_msg: Text displayed in header
:item_list: Dict() containing all data about item (see `get_data_list()`)
:result:
- item:
- cli_end_msg:
- valid_item:
"""
valid_input = False
foot_msg = ""
while valid_input is False:
system('clear')
print(head_msg)
print(item_list['results_txt'])
print(foot_msg)
user_input = input(CLI_MSG_ASK_IDX.format(item_list['max_id']))
if user_input.lower() == "q":
valid_input = True
valid_item = False
item = ""
else:
try:
user_input = int(user_input)
# Response not int(), re-ask
except ValueError:
foot_msg += CLI_MSG_ASK_ERR.format(user_input)
else:
# Response is valid
if user_input <= item_list['max_id']:
valid_input = True
valid_item = True
item = item_list['results_list'][user_input]
# Response not in range, re-ask
else:
foot_msg += CLI_MSG_ASK_ERR.format(user_input)
return {
'item': item,
'cli_end_msg': foot_msg,
'valid_item': valid_item
}
def get_data_list(db_obj, sql):
"""
Gets data from DB & return them formated as a text list displayable on CLI
:db_obj: a database object [PyMySQL]
:sql: a SQL query
:Return: a dict containing details on requested data:
- max_id: maximum ID
- results_list: stored in a list of tuple (id, name, count)
- results_txt: in a string, text-formated
"""
db_obj.execute(sql)
max_id = int(db_obj.cursor.rowcount - 1)
results_list = [(idx, val['name'], val['option'], val['id'])
for idx, val in enumerate(db_obj.result)]
# Hacky results-split for rendering in 2 columns
res_even = [(
idx,
val['name'][:CLI_MAX_LEN].ljust(CLI_MAX_LEN),
val['option'], val['id']
) for idx, val in enumerate(db_obj.result) if idx % 2 == 0]
res_uneven = [(
idx,
val['name'][:CLI_MAX_LEN],
val['option'],
val['id']
) for idx, val in enumerate(db_obj.result) if idx % 2 != 0]
# category list
results_txt = ""
if len(res_uneven) == 0 and len(res_even) > 0:
results_txt += "{} : {}\n".format(
res_even[0][0],
res_even[0][1]
)
else:
for num, unused in enumerate(res_uneven):
results_txt += CLI_ITEM_LIST.format(
res_even[num][0],
res_even[num][1],
res_uneven[num][0],
res_uneven[num][1]
)
if len(res_uneven) < len(res_even):
num += 1
results_txt += "{} : {}\n".format(
res_even[num][0],
res_even[num][1]
)
return {
'max_id': max_id,
'results_list': results_list,
'results_txt': results_txt
}
def start_init_menu():
""" Ask for saved substitution or searching new one """
LOCAL_DB.execute(DB_REQUEST['list_substituated_prod'])
if LOCAL_DB.cursor.rowcount > 0:
menu_list = {
'results_txt': CLI_MSG_INIT_MENU,
'results_list': [False, True],
'max_id': 1
}
# Ask for saved list or search new one
menu_asked = ask_user(
CLI_MSG_DISCLAIMER,
menu_list
)
# Shows saved list
if menu_asked['valid_item'] and menu_asked['item']:
cli_msg_subst_recap = CLI_MSG_SUBST_TITLE + CLI_MSG_SUBST_HEAD
for row in LOCAL_DB.result:
cli_msg_subst_recap += CLI_MSG_SUBST_LIST.format(
pname=row['pname'][:CLI_MAX_LEN].center(CLI_MAX_LEN),
sname=row['sname'][:CLI_MAX_LEN].center(CLI_MAX_LEN),
)
return (True, cli_msg_subst_recap)
return (False, "")
return (False, "Pas de substitutions enregistée")
# Starts a DB connection
LOCAL_DB = Db()
################
# INITIAL MENU #
################
init_menu = start_init_menu()
#############################
# LISTS SAVED SUBSTITUTIONS #
#############################
if init_menu[0]:
cli_end_msg = init_menu[1]
####################
# LISTS CATEGORIES #
####################
else:
category_list = get_data_list(
LOCAL_DB,
DB_REQUEST['list_cat']
)
head_msg = CLI_MSG_DISCLAIMER
head_msg += init_menu[1]
head_msg += CLI_MSG_CAT
# Asks the user to select a category
category_asked = ask_user(
head_msg,
category_list
)
##################
# LISTS PRODUCTS #
##################
if category_asked['valid_item']:
product_list = get_data_list(
LOCAL_DB,
DB_REQUEST['list_prod'].format(category_asked['item'][3])
)
head_msg = CLI_MSG_DISCLAIMER
head_msg += CLI_MSG_CHOOSEN_CAT.format(category_asked['item'][1])
head_msg += CLI_MSG_PROD
# Asks the user to select a product
product_asked = ask_user(
head_msg,
product_list
)
####################
# LISTS SUBTITUTES #
####################
if product_asked['valid_item']:
substitute_list = get_data_list(
LOCAL_DB,
DB_REQUEST['list_substitute'].format(
category_asked['item'][3],
product_asked['item'][2]
)
)
head_msg = CLI_MSG_DISCLAIMER
head_msg += CLI_MSG_CHOOSEN_CAT.format(category_asked['item'][1])
head_msg += CLI_MSG_CHOOSEN_PROD.format(product_asked['item'][1])
head_msg += CLI_MSG_SUBST
# No substitute found
if substitute_list['max_id'] == -1:
cli_end_msg = CLI_MSG_NO_SUBST.format(
product_asked['item'][1],
product_asked['item'][2]
)
# Asks the user to select a substitute
elif substitute_list['max_id'] >= 0:
substit_asked = ask_user(
head_msg,
substitute_list
)
##########################
# SHOW SUBTITUTE DETAILS #
##########################
if substit_asked['valid_item']:
LOCAL_DB.execute(DB_REQUEST['select_substitute'].format(
substit_asked['item'][3]
))
head_msg = CLI_MSG_DISCLAIMER +\
CLI_MSG_CHOOSEN_CAT.format(substit_asked['item'][1])
backup_list = {
'results_txt': CLI_MSG_DETAILLED_SUB.format(
code=LOCAL_DB.result[0]['code'],
nutri=LOCAL_DB.result[0]['nutrition_grades'],
url=LOCAL_DB.result[0]['url']
) + CLI_MSG_ASK_BAK.format(
substit_asked['item'][1],
product_asked['item'][1]
),
'results_list': [False, True],
'max_id': 1
}
# Saves if user choose it
backup_asked = ask_user(
head_msg,
backup_list
)
if backup_asked['valid_item'] and backup_asked['item']:
LOCAL_DB.execute(DB_REQUEST['save_substitute'].format(
substit_asked['item'][3],
product_asked['item'][3]
))
if LOCAL_DB.cursor.rowcount == 1:
cli_end_msg = CLI_MSG_BAK_DONE
print(cli_end_msg)