Skip to content

Instantly share code, notes, and snippets.

@NP-chaonay
Last active October 7, 2020 15:05
Show Gist options
  • Save NP-chaonay/705012250c48323d18b5d248bfd4a22b to your computer and use it in GitHub Desktop.
Save NP-chaonay/705012250c48323d18b5d248bfd4a22b to your computer and use it in GitHub Desktop.
Python script for viewing/manipulating to-do list, designed for academic usage.
#!/usr/bin/env python3
# Name: Academic Todo Recording
# Description: Program helps you deal with entries of academic todo record.
# Author: NP-chaonay (Nuttapong Punpipat)
# Version: 0.0.0_alpha
# Version Note:
# - Major version: File produced on different major version is not compatible
# - Minor version: Features adding
# - Micro version: Bugs fixing
# Revised Date: 2020-08-09 15:13 (UTC)
# License: MIT License
# Programming Language: Python
# CUI/GUI Language: English
# Development Stage :
# [/] Reviewing of Code
# [] Reviewing of Type and Value Checking & Error Handling
# [] Reviewing of Documentations
# [] Testing
## Importing modules
import np_chaonay.main as npc_m
import re,sys,os,time,getopt
import pandas as pd
import warnings
##
## Defining functions
def ask_csv(prompt_msg):
while True:
var=input(prompt_msg+': ').strip()
if ',' in var: npc_m.print_categorical_bracket('ERROR','Inputted text should not consist of comma.')
else: break
return var
def ask_csv_date(prompt_msg):
while True:
var=ask_csv(prompt_msg)
if var=='': break
elif not re.match(r'^([0-9]){6}$',var): npc_m.print_categorical_bracket('ERROR','Inputted text should use specificied date format.')
else: break
return var
def load_df():
df=pd.read_csv(FILE_PATH,header=None,names=('Group','Subject','Assigned Date','Optimal Doing Date','Due Date','Importance','Description'),dtype=DTYPE)
return df
def sort(df,sort_method='user1'):
if sort_method=='user1':
tmp_df=df.copy()
# Regular sorting
tmp_df.loc[:,'Optimal Doing Date']=df.loc[:,'Optimal Doing Date'].astype('float')
tmp_df.loc[:,'Importance']=df.loc[:,'Importance'].astype('float')
tmp_df.loc[:,'TimeWeight']=df.loc[:,'Subject'].agg(lambda name: TIMEWEIGHT.get(name,1))
tmp_df.loc[:,'Due Date']=df.loc[:,'Due Date'].astype('float')
tmp_df.loc[:,'Assigned Date']=df.loc[:,'Assigned Date'].astype('float')
tmp_df=df.iloc[tmp_df.sort_values(['Optimal Doing Date','Importance','TimeWeight','Due Date','Assigned Date'],ascending=[True,False,False,True,True],kind='mergesort').index]
#
return tmp_df
else:
npc_m.print_categorical_bracket('ERROR','Unknown sort method \''+sort_method+'\'.')
exit(2)
def process_then_print_df(df,date_offset=0):
tmp_df=df.copy()
datetime=time.localtime(time.time()+(24*60*60)*date_offset)
datetime=datetime[0]%100*10000+datetime[1]*100+datetime[2]
tmp_df['Optimal Doing Date Distance']=tmp_df['Optimal Doing Date'].astype('float')-datetime
tmp_df['Due Date Distance']=tmp_df['Due Date'].astype('float')-datetime
tmp_df['TimeWeight']=tmp_df['Subject'].agg(lambda name: TIMEWEIGHT.get(name,DEFAULT_TIMEWEIGHT))
tmp_df['Status']='UNKNOWN'
tmp_df['Status']=tmp_df.Status.astype('category')
tmp_df.Status.cat.add_categories(['No both date','Not on time','Normal','Normal (No due date)','Recommended','Recommended (No due date)','Warning','Warning (No due date)','Dangerous','Lated'],inplace=True)
#
no_recommended_date_entries=pd.isna(tmp_df.loc[:,'Optimal Doing Date'].astype('float').values)
no_due_date_entries=pd.isna(tmp_df.loc[:,'Due Date'].astype('float').values)
no_both_date_entries=no_recommended_date_entries&no_due_date_entries
#
late_entries=datetime>tmp_df.loc[:,'Due Date'].astype('float').values
ontime_entries=datetime==tmp_df.loc[:,'Due Date'].astype('float').values
#
after_recommended_date_entries=datetime>tmp_df.loc[:,'Optimal Doing Date'].astype('float').values
on_recommended_date_entries=datetime==tmp_df.loc[:,'Optimal Doing Date'].astype('float').values
ahead_recommended_date_entries=datetime<tmp_df.loc[:,'Optimal Doing Date'].astype('float').values
#
no_due_date_after_recommended_date_entries=no_due_date_entries&(datetime>tmp_df.loc[:,'Optimal Doing Date'].astype('float').values)
no_due_date_on_recommended_date_entries=no_due_date_entries&(datetime==tmp_df.loc[:,'Optimal Doing Date'].astype('float').values)
no_due_date_ahead_recommended_date_entries=no_due_date_entries&(datetime<tmp_df.loc[:,'Optimal Doing Date'].astype('float').values)
# Program code arranging may be required for correct masking.
tmp_df.Status.mask(no_recommended_date_entries,'Not on time',inplace=True)
tmp_df.Status.mask(no_both_date_entries,'No both date',inplace=True)
tmp_df.Status.mask(ahead_recommended_date_entries,'Normal',inplace=True)
tmp_df.Status.mask(no_due_date_ahead_recommended_date_entries,'Normal (No due date)',inplace=True)
tmp_df.Status.mask(on_recommended_date_entries,'Recommended',inplace=True)
tmp_df.Status.mask(no_due_date_on_recommended_date_entries,'Recommended (No due date)',inplace=True)
tmp_df.Status.mask(after_recommended_date_entries,'Warning',inplace=True)
tmp_df.Status.mask(no_due_date_after_recommended_date_entries,'Warning (No due date)',inplace=True)
tmp_df.Status.mask(ontime_entries,'Dangerous',inplace=True)
tmp_df.Status.mask(late_entries,'Lated',inplace=True)
#
with pd.option_context('display.max_rows', None, 'display.max_columns', None):
print(tmp_df[print_df_cols])
def df_cut(df,start_index=None,end_index=None,start_pos=None,end_pos=None,length_from_start=None,length_from_end=None):
if start_pos is None: start_pos=1
if length_from_end is None: length_from_end=0
return df.loc[start_index:end_index].iloc[start_pos-1:end_pos].iloc[-length_from_end:length_from_start]
##
## User parameters
# File name (Used in DEFAULT_FILEPATH)
FILE_NAME='Todo_Academic_Record.csv'
# Default database path
DEFAULT_FILEPATH='/sdcard/Temporary/'+FILE_NAME
# Default timeweight
DEFAULT_TIMEWEIGHT=1.0
# Timeweight of subject (Undefined subject has a timeweight value as DEFAULT_TIMEWEIGHT)
TIMEWEIGHT={
# ความสำคัญสูงมาก
'I-GENERAL':10,
# วิชาที่ระบุหน่วยกิต
'SUPPMATH':2,
'PHYSICS':2,
'PHYSIC':2,
'CHEM':1.5,
'BIO':1.5,
'HE':0.5,
'MART':0.5,
'MUSIC':0.5,
'ART':0.5,
# พลศึกษาไม่ได้ระบุไว้ในคู่มือฯ ฉะนั้นกำหนดให้มีค่าเหมือน "สุขศึกษา"
'PE':0.5,
# แนะแนว น่าจะเทียบเท่า 0.5
'LIFEC':0.5,
'COUN':0.5,
# บำเพ็ญประโยชน์/ร.ด./จิตอาสาอื่น ๆ น่าจะเทียบเท่า 0.5
'HELP':0.5,
'RD':0.5,
'VOL':0.5,
# ชมรม น่าจะเทียบเท่า 0.5
'CLUB':0.5,
}
# Set columns displaying order
print_df_cols=['Optimal Doing Date Distance','Due Date Distance','Status','Importance','TimeWeight','Optimal Doing Date','Due Date','Assigned Date','Subject','Group','Description']
##
## Program Initialization
warnings.filterwarnings('ignore','',RuntimeWarning)
DTYPE={
'Group':'category',
'Subject':'category',
'Assigned Date':'str',
'Optimal Doing Date':'str',
'Due Date':'str',
'Importance':'category',
'Description':'str',
}
##
## Command-line parsing
options=dict()
try: command=sys.argv[1]
except IndexError:
npc_m.print_categorical_bracket('ERROR','Command unspecified.')
exit(2)
if len(sys.argv)>2:
args=sys.argv[2:]
try: options,args=getopt.getopt(args,'',['file-path=','start-index=','end-index=','start-pos=','end-pos=','length-from-start=','length-from-end=','date-offset='])
except getopt.GetoptError as err:
npc_m.print_categorical_bracket('ERROR','Unrecognized or argument-needed option \''+err.opt+'\'.')
exit(2)
options=dict(options)
### Default parameters
FILE_PATH=options.get('--file-path',DEFAULT_FILEPATH)
start_index=options.get('--start-index',None)
end_index=options.get('--end-index',None)
start_pos=options.get('--start-pos',None)
end_pos=options.get('--end-pos',None)
length_from_start=options.get('--length-from-start',None)
length_from_end=options.get('--length-from-end',None)
date_offset=options.get('--date-offset',0)
### Checking typed arguments
tmp_bool_1='--start-index' in options
tmp_bool_2='--end-index' in options
tmp_bool_3='--start-pos' in options
tmp_bool_4='--end-pos' in options
tmp_bool_5='--length-from-start' in options
tmp_bool_6='--length-from-end' in options
if tmp_bool_5 and tmp_bool_6:
npc_m.print_categorical_bracket('ERROR','--length-from-start and --length-from-end cannot be specified simultaneously.')
exit(2)
tmp=(tmp_bool_1,tmp_bool_3,tmp_bool_6)
if not npc_m.is_only_one_True(tmp) and any(tmp):
npc_m.print_categorical_bracket('ERROR','--start-index, --start-pos, and --length-from-end cannot be specified simultaneously.')
exit(2)
tmp=(tmp_bool_2,tmp_bool_4,tmp_bool_5)
if not npc_m.is_only_one_True(tmp) and any(tmp):
npc_m.print_categorical_bracket('ERROR','--end-index, --end-pos, and --length-from-start cannot be specified simultaneously.')
exit(2)
### Checking string type
if start_index is None: pass
elif npc_m.is_integer_string(start_index): start_index=int(start_index)
else:
npc_m.print_categorical_bracket('ERROR','--start-index argument must be integer.')
exit(2)
if end_index is None: pass
elif npc_m.is_integer_string(end_index): end_index=int(end_index)
else:
npc_m.print_categorical_bracket('ERROR','--end-index argument must be integer.')
exit(2)
if start_pos is None: pass
elif npc_m.is_integer_string(start_pos): start_pos=int(start_pos)
else:
npc_m.print_categorical_bracket('ERROR','--start-pos argument must be integer.')
exit(2)
if end_pos is None: pass
elif npc_m.is_integer_string(end_pos): end_pos=int(end_pos)
else:
npc_m.print_categorical_bracket('ERROR','--end-pos argument must be integer.')
exit(2)
if length_from_start is None: pass
elif npc_m.is_integer_string(length_from_start): length_from_start=int(length_from_start)
else:
npc_m.print_categorical_bracket('ERROR','--length-from-start argument must be integer.')
exit(2)
if length_from_end is None: pass
elif npc_m.is_integer_string(length_from_end): length_from_end=int(length_from_end)
else:
npc_m.print_categorical_bracket('ERROR','--length-from-end argument must be integer.')
exit(2)
if date_offset==0: pass
elif npc_m.is_integer_string(date_offset): date_offset=float(date_offset)
else:
npc_m.print_categorical_bracket('ERROR','--date-offset argument must be integer/decimal.')
exit(2)
### Checking for "FILE_PATH"
if FILE_PATH=='':
npc_m.print_categorical_bracket('ERROR','--file-path argument must not be empty.')
exit(2)
### Checking values
if start_index!=None:
if start_index<0:
if start_index==-1: start_index=None
else:
npc_m.print_categorical_bracket('ERROR','--start-index argument must not less than 0 or must be -1.')
exit(2)
if end_index!=None:
if end_index<0:
if end_index==-1: end_index=None
else:
npc_m.print_categorical_bracket('ERROR','--end-index argument must not less than 0 or must be -1.')
exit(2)
if start_pos!=None:
if start_pos<1:
if start_pos==-1: start_pos=None
else:
npc_m.print_categorical_bracket('ERROR','--start-pos argument must not less than 1 or must be -1.')
exit(2)
if end_pos!=None:
if end_pos<1:
if end_pos==-1: end_pos=None
else:
npc_m.print_categorical_bracket('ERROR','--end-pos argument must not less than 1 or must be -1.')
exit(2)
if length_from_start!=None:
if length_from_start<1:
if length_from_start==-1: length_from_start=None
else:
npc_m.print_categorical_bracket('ERROR','--length-from-start argument must not less than 1 or must be -1.')
exit(2)
if length_from_end!=None:
if length_from_end<1:
if length_from_end==-1: length_from_end=None
else:
npc_m.print_categorical_bracket('ERROR','--length-from-start argument must not less than 1 or must be -1.')
exit(2)
###
##
## Command checking then doing corresponding action
# Registration
if command=='reg':
try:
f_group=ask_csv('Group').upper()
f_subject=ask_csv('Subject').upper()
f_assigned_date=ask_csv_date('Assigned Date')
f_due_date=ask_csv_date('Due Date')
f_optimal_doing_date=ask_csv_date('Optimal Doing Date')
f_description=ask_csv('Description')
while True:
f_importance=ask_csv('Importance')
if f_importance not in ['-1','0','1','']:
npc_m.print_categorical_bracket('ERROR','Inputted text should be -1,0,1.')
continue
else: break
except (KeyboardInterrupt,EOFError): exit(0)
data=f_group+','+f_subject+','+f_assigned_date+','+f_optimal_doing_date+','+f_due_date+','+f_importance+','+f_description+'\n'
open(FILE_PATH,'a').write(data)
# Printing result using user-implementaion method
elif command=='userread':
df=sort(load_df())
df=df_cut(df,start_index,end_index,start_pos,end_pos,length_from_start,length_from_end)
process_then_print_df(df,date_offset)
elif command=='readdesc':
if not npc_m.is_integer_string(args[0]):
npc_m.print_categorical_bracket('ERROR','Index must be integer.')
exit(2)
index=int(args[0])
if index<0:
npc_m.print_categorical_bracket('ERROR','Index must be positive or zero integer.')
exit(2)
try: print(load_df().loc[int(args[0]),'Description'])
except KeyError:
npc_m.print_categorical_bracket('ERROR','Data is not available at specified index.')
exit(2)
else:
npc_m.print_categorical_bracket('ERROR','Unknown command \''+command+'\'.'); exit(1)
##
#!/usr/bin/env python3
# Name: Academic Todo Recording
# Description: Program helps you deal with entries of academic todo record.
# Author: NP-chaonay (Nuttapong Punpipat)
# Version: 1.1.0_alpha
# Version Note:
# - Major version: File produced on different major version is not compatible
# - Minor version: Features adding
# - Micro version: Bugs fixing
# Revised Date: 2020-07-28 06:02 (UTC)
# License: MIT License
# Programming Language: Python
# CUI/GUI Language: English
# Development Stage :
# [/] Reviewing of Code
# [] Reviewing of Type and Value Checking & Error Handling
# [] Reviewing of Documentations
# [] Testing
## Importing modules
import np_chaonay.main as npc_m
import re,sys,os,time,getopt,datetime
import numpy as np
import pandas as pd
import warnings
##
## User parameters
# File name (Used in DEFAULT_FILEPATH)
FILE_NAME='Todo_Academic_Record.csv'
# Default database path
DEFAULT_FILEPATH='/sdcard/Temporary/'+FILE_NAME
# Default timeweight
DEFAULT_TIMEWEIGHT=1.0
# Timeweight of subject (Undefined subject has a timeweight value as DEFAULT_TIMEWEIGHT)
TIMEWEIGHT={
# ความสำคัญสูงมาก
'I-GENERAL':10,
# วิชาที่ระบุหน่วยกิต
'SUPPMATH':2,
'PHYSICS':2,
'PHYSIC':2,
'CHEM':1.5,
'BIO':1.5,
'HE':0.5,
'MART':0.5,
'MUSIC':0.5,
'ART':0.5,
# พลศึกษาไม่ได้ระบุไว้ในคู่มือฯ ฉะนั้นกำหนดให้มีค่าเหมือน "สุขศึกษา"
'PE':0.5,
# แนะแนว น่าจะเทียบเท่า 0.5
'LIFEC':0.5,
'COUN':0.5,
# บำเพ็ญประโยชน์/ร.ด./จิตอาสาอื่น ๆ น่าจะเทียบเท่า 0.5
'HELP':0.5,
'RD':0.5,
'VOL':0.5,
# ชมรม น่าจะเทียบเท่า 0.5
'CLUB':0.5,
}
# Set columns displaying's ordering and formatting
PRINT_DF_COLS=[
['Subject','Group','Status','Importance','TimeWeight',],
['SafeDeadlineDistance','OptimalDeadlineDistance','MinimalDeadlineDistance','DueDateDistance',],
['AssignedDate','SafeDeadline','OptimalDeadline','MinimalDeadline','DueDate'],
['Description'],
]
# Set default sorting method
DEFAULT_SORT_METHOD='default'
##
## Defining functions
def ask_csv(prompt_msg):
while True:
var=input(prompt_msg+': ').strip()
if ',' in var: npc_m.print_categorical_bracket('ERROR','Inputted text should not consist of comma.')
else: break
return var
def ask_csv_date(prompt_msg):
while True:
var=ask_csv(prompt_msg)
if var=='': break
elif not re.match(r'^([0-9]){6}$',var): npc_m.print_categorical_bracket('ERROR','Inputted text should use specificied date format.')
else: break
return var
def load_df():
df=pd.read_csv(FILE_PATH,header=None,names=('Group','Subject','AssignedDate','SafeDeadline','OptimalDeadline','MinimalDeadline','DueDate','Importance','Description'),dtype=DTYPE)
return df
def sort(df,sort_method):
if sort_method=='opti1':
tmp_df=df.copy()
tmp_df.loc[:,'OptimalDeadline']=df.loc[:,'OptimalDeadline'].astype('float')
tmp_df.loc[:,'MinimalDeadline']=df.loc[:,'MinimalDeadline'].astype('float')
tmp_df.loc[:,'Importance']=df.loc[:,'Importance'].astype('float')
tmp_df.loc[:,'SafeDeadline']=df.loc[:,'SafeDeadline'].astype('float')
tmp_df.loc[:,'TimeWeight']=df.loc[:,'Subject'].agg(lambda name: TIMEWEIGHT.get(name,DEFAULT_TIMEWEIGHT))
tmp_df.loc[:,'DueDate']=df.loc[:,'DueDate'].astype('float')
tmp_df.loc[:,'AssignedDate']=df.loc[:,'AssignedDate'].astype('float')
tmp_df=tmp_df.reset_index().sort_values(['OptimalDeadline','MinimalDeadline','Importance','SafeDeadline','TimeWeight','DueDate','AssignedDate','index'],ascending=[True,True,False,True,False,True,True,True],kind='mergesort',na_position='first').set_index('index')
tmp_df.index.name=None
tmp_df=df.iloc[tmp_df.index]
return tmp_df
elif sort_method=='byassign-as':
tmp_df=df.copy()
tmp_df.loc[:,'AssignedDate']=df.loc[:,'AssignedDate'].astype('float')
tmp_df=tmp_df.reset_index().sort_values(['AssignedDate','index'],ascending=False,kind='mergesort',na_position='first').set_index('index')
tmp_df.index.name=None
tmp_df=df.iloc[tmp_df.index]
return tmp_df
elif sort_method=='byassign-de':
tmp_df=df.copy()
tmp_df.loc[:,'AssignedDate']=df.loc[:,'AssignedDate'].astype('float')
tmp_df=tmp_df.reset_index().sort_values(['AssignedDate','index'],ascending=True,kind='mergesort',na_position='first').set_index('index')
tmp_df.index.name=None
tmp_df=df.iloc[tmp_df.index]
return tmp_df
elif sort_method=='opti2':
tmp_df=df.copy()
tmp_df.loc[:,'OptimalDeadline']=df.loc[:,'OptimalDeadline'].astype('float')
tmp_df.loc[:,'MinimalDeadline']=df.loc[:,'MinimalDeadline'].astype('float')
tmp_df.loc[:,'Importance']=df.loc[:,'Importance'].astype('float')
tmp_df.loc[:,'SafeDeadline']=df.loc[:,'SafeDeadline'].astype('float')
tmp_df.loc[:,'TimeWeight']=df.loc[:,'Subject'].agg(lambda name: TIMEWEIGHT.get(name,DEFAULT_TIMEWEIGHT))
tmp_df.loc[:,'DueDate']=df.loc[:,'DueDate'].astype('float')
tmp_df.loc[:,'AssignedDate']=df.loc[:,'AssignedDate'].astype('float')
tmp_df=tmp_df.reset_index().sort_values(['DueDate','MinimalDeadline','OptimalDeadline','Importance','TimeWeight','SafeDeadline','AssignedDate','index'],ascending=[True,True,True,False,False,True,True,True],kind='mergesort',na_position='first').set_index('index')
tmp_df.index.name=None
tmp_df=df.iloc[tmp_df.index]
return tmp_df
elif sort_method=='opti2-imp-first':
tmp_df=df.copy()
tmp_df.loc[:,'OptimalDeadline']=df.loc[:,'OptimalDeadline'].astype('float')
tmp_df.loc[:,'MinimalDeadline']=df.loc[:,'MinimalDeadline'].astype('float')
tmp_df.loc[:,'Importance']=df.loc[:,'Importance'].astype('float')
tmp_df.loc[:,'SafeDeadline']=df.loc[:,'SafeDeadline'].astype('float')
tmp_df.loc[:,'TimeWeight']=df.loc[:,'Subject'].agg(lambda name: TIMEWEIGHT.get(name,DEFAULT_TIMEWEIGHT))
tmp_df.loc[:,'DueDate']=df.loc[:,'DueDate'].astype('float')
tmp_df.loc[:,'AssignedDate']=df.loc[:,'AssignedDate'].astype('float')
tmp_df=tmp_df.reset_index().sort_values(['Importance','DueDate','MinimalDeadline','OptimalDeadline','TimeWeight','SafeDeadline','AssignedDate','index'],ascending=[False,True,True,True,False,True,True,True],kind='mergesort',na_position='first').set_index('index')
tmp_df.index.name=None
tmp_df=df.iloc[tmp_df.index]
return tmp_df
elif sort_method=='default' or sort_method=='bydate-as':
tmp_df=df.copy()
tmp_df.loc[:,'OptimalDeadline']=df.loc[:,'OptimalDeadline'].astype('float')
tmp_df.loc[:,'MinimalDeadline']=df.loc[:,'MinimalDeadline'].astype('float')
tmp_df.loc[:,'Importance']=df.loc[:,'Importance'].astype('float')
tmp_df.loc[:,'SafeDeadline']=df.loc[:,'SafeDeadline'].astype('float')
tmp_df.loc[:,'TimeWeight']=df.loc[:,'Subject'].agg(lambda name: TIMEWEIGHT.get(name,DEFAULT_TIMEWEIGHT))
tmp_df.loc[:,'DueDate']=df.loc[:,'DueDate'].astype('float')
tmp_df.loc[:,'AssignedDate']=df.loc[:,'AssignedDate'].astype('float')
tmp_df=tmp_df.reset_index().sort_values(['DueDate','MinimalDeadline','OptimalDeadline','SafeDeadline','Importance','TimeWeight','AssignedDate','index'],ascending=[True,True,True,True,False,False,True,True],kind='mergesort',na_position='first').set_index('index')
tmp_df.index.name=None
tmp_df=df.iloc[tmp_df.index]
return tmp_df
else:
npc_m.print_categorical_bracket('ERROR','Unknown sort method \''+sort_method+'\'.')
exit(2)
def process_then_print_df(df,date_offset=0):
global current_date
tmp_df=df.copy()
current_date=time.localtime(time.time()+(24*60*60)*date_offset)
current_date=npc_m.add_lead_zero(current_date[0],2,True)[-2:]+npc_m.add_lead_zero(current_date[1],2)+npc_m.add_lead_zero(current_date[2],2)
current_date=datestr_to_date(current_date)
tmp_df['TimeWeight']=tmp_df['Subject'].agg(lambda name: TIMEWEIGHT.get(name,DEFAULT_TIMEWEIGHT))
tmp_df['SafeDeadlineDistance']=tmp_df['SafeDeadline'].agg(date_diff_func)
tmp_df['OptimalDeadlineDistance']=tmp_df['OptimalDeadline'].agg(date_diff_func)
tmp_df['MinimalDeadlineDistance']=tmp_df['MinimalDeadline'].agg(date_diff_func)
tmp_df['DueDateDistance']=tmp_df['DueDate'].agg(date_diff_func)
## STATUS
tmp_df['Status']=tmp_df[['SafeDeadline','OptimalDeadline','MinimalDeadline','DueDate']].agg(status_picker,axis=1)
##
with pd.option_context('display.max_rows', None, 'display.max_columns', None):
tmp_df=tmp_df.groupby('Importance')
for group in tmp_df.groups:
print('################ Importance:'+str(group)+' ################')
for cols in PRINT_DF_COLS:
print(tmp_df.get_group(group)[cols])
print('###############################################\n')
def df_cut(df,start_index=None,end_index=None,start_pos=None,end_pos=None,length_from_start=None,length_from_end=None):
if start_pos is None: start_pos=1
if length_from_end is None: length_from_end=0
return df.loc[start_index:end_index].iloc[start_pos-1:end_pos].iloc[-length_from_end:length_from_start]
def status_picker(series):
## Initialzation
series=tuple(map(datestr_to_date,series))
series=np.array(series)
## Find equal position / nearest position
if current_date==series[0]: pos=(0,)
elif current_date==series[1]: pos=(1,)
elif current_date==series[2]: pos=(2,)
elif current_date==series[3]: pos=(3,)
else:
upper=[]
lower=[]
lower+=[-1]
if series[0]:
if current_date>series[0]: lower+=[0]
if current_date<series[0]: upper+=[0]
if series[1]:
if current_date>series[1]: lower+=[1]
if current_date<series[1]: upper+=[1]
if series[2]:
if current_date>series[2]: lower+=[2]
if current_date<series[2]: upper+=[2]
if series[3]:
if current_date>series[3]: lower+=[3]
if current_date<series[3]: upper+=[3]
upper+=[-1]
pos=(lower[-1],upper[0])
## Find postions with duplicated value
if len(pos)==2:
if pos[0]==-1: match_date_lower=[-1]
else: match_date_lower=np.where(series==series[pos[0]])[0]
if pos[1]==-1: match_date_upper=[-1]
else: match_date_upper=np.where(series==series[pos[1]])[0]
else: match_date=np.where(series==series[pos])[0]
## Pick up corresponding message string
message=np.array(('Safe','Optimal','Minimal','Due'))
if len(pos)==2:
if pos[0]==-1 and pos[1]!=-1: return 'Before '+','.join(message[match_date_upper])+' date'
elif pos[0]!=-1 and pos[1]==-1: return 'After '+','.join(message[match_date_lower])+' date'
elif pos[0]==-1 and pos[1]==-1: return 'DeadlineDateIsNotDefined'
else: return 'Between '+','.join(message[match_date_lower])+' and '+','.join(message[match_date_upper])+' date'
else: return 'On '+','.join(message[match_date])+' date'
def datestr_to_date(datestr):
if datestr!=datestr: return None
else:
y=int(datestr[0:2])
m=int(datestr[2:4])
d=int(datestr[4:6])
return datetime.date(y,m,d)
def date_diff_func(datestr):
given_date=datestr_to_date(datestr)
if given_date:
return ( given_date-current_date ).days
else: return float('nan')
##
## Program Initialization
warnings.filterwarnings('ignore','',RuntimeWarning)
DTYPE={
'Group':'category',
'Subject':'category',
'AssignedDate':'str',
'SafeDeadline':'str',
'OptimalDeadline':'str',
'MinimalDeadline':'str',
'DueDate':'str',
'Importance':'category',
'Description':'str',
}
##
## Command-line parsing
options=dict()
try: command=sys.argv[1]
except IndexError:
npc_m.print_categorical_bracket('ERROR','Command unspecified.')
exit(2)
if len(sys.argv)>2:
args=sys.argv[2:]
try: options,args=getopt.getopt(args,'',['file-path=','start-index=','end-index=','start-pos=','end-pos=','length-from-start=','length-from-end=','date-offset=','sort-method='])
except getopt.GetoptError as err:
npc_m.print_categorical_bracket('ERROR','Unrecognized or argument-needed option \''+err.opt+'\'.')
exit(2)
options=dict(options)
### Default parameters
FILE_PATH=options.get('--file-path',DEFAULT_FILEPATH)
start_index=options.get('--start-index',None)
end_index=options.get('--end-index',None)
start_pos=options.get('--start-pos',None)
end_pos=options.get('--end-pos',None)
length_from_start=options.get('--length-from-start',None)
length_from_end=options.get('--length-from-end',None)
date_offset=options.get('--date-offset',0)
sort_method=options.get('--sort-method',DEFAULT_SORT_METHOD)
### Checking typed arguments
tmp_bool_1='--start-index' in options
tmp_bool_2='--end-index' in options
tmp_bool_3='--start-pos' in options
tmp_bool_4='--end-pos' in options
tmp_bool_5='--length-from-start' in options
tmp_bool_6='--length-from-end' in options
if tmp_bool_5 and tmp_bool_6:
npc_m.print_categorical_bracket('ERROR','--length-from-start and --length-from-end cannot be specified simultaneously.')
exit(2)
tmp=(tmp_bool_1,tmp_bool_3,tmp_bool_6)
if not npc_m.is_only_one_True(tmp) and any(tmp):
npc_m.print_categorical_bracket('ERROR','--start-index, --start-pos, and --length-from-end cannot be specified simultaneously.')
exit(2)
tmp=(tmp_bool_2,tmp_bool_4,tmp_bool_5)
if not npc_m.is_only_one_True(tmp) and any(tmp):
npc_m.print_categorical_bracket('ERROR','--end-index, --end-pos, and --length-from-start cannot be specified simultaneously.')
exit(2)
### Checking string type
if start_index is None: pass
elif npc_m.is_integer_string(start_index): start_index=int(start_index)
else:
npc_m.print_categorical_bracket('ERROR','--start-index argument must be integer.')
exit(2)
if end_index is None: pass
elif npc_m.is_integer_string(end_index): end_index=int(end_index)
else:
npc_m.print_categorical_bracket('ERROR','--end-index argument must be integer.')
exit(2)
if start_pos is None: pass
elif npc_m.is_integer_string(start_pos): start_pos=int(start_pos)
else:
npc_m.print_categorical_bracket('ERROR','--start-pos argument must be integer.')
exit(2)
if end_pos is None: pass
elif npc_m.is_integer_string(end_pos): end_pos=int(end_pos)
else:
npc_m.print_categorical_bracket('ERROR','--end-pos argument must be integer.')
exit(2)
if length_from_start is None: pass
elif npc_m.is_integer_string(length_from_start): length_from_start=int(length_from_start)
else:
npc_m.print_categorical_bracket('ERROR','--length-from-start argument must be integer.')
exit(2)
if length_from_end is None: pass
elif npc_m.is_integer_string(length_from_end): length_from_end=int(length_from_end)
else:
npc_m.print_categorical_bracket('ERROR','--length-from-end argument must be integer.')
exit(2)
if date_offset==0: pass
elif npc_m.is_integer_string(date_offset): date_offset=int(date_offset)
else:
npc_m.print_categorical_bracket('ERROR','--date-offset argument must be integer.')
exit(2)
### Checking for "FILE_PATH"
if FILE_PATH=='':
npc_m.print_categorical_bracket('ERROR','--file-path argument must not be empty.')
exit(2)
### Checking values
if start_index!=None:
if start_index<0:
if start_index==-1: start_index=None
else:
npc_m.print_categorical_bracket('ERROR','--start-index argument must not less than 0 or must be -1.')
exit(2)
if end_index!=None:
if end_index<0:
if end_index==-1: end_index=None
else:
npc_m.print_categorical_bracket('ERROR','--end-index argument must not less than 0 or must be -1.')
exit(2)
if start_pos!=None:
if start_pos<1:
if start_pos==-1: start_pos=None
else:
npc_m.print_categorical_bracket('ERROR','--start-pos argument must not less than 1 or must be -1.')
exit(2)
if end_pos!=None:
if end_pos<1:
if end_pos==-1: end_pos=None
else:
npc_m.print_categorical_bracket('ERROR','--end-pos argument must not less than 1 or must be -1.')
exit(2)
if length_from_start!=None:
if length_from_start<1:
if length_from_start==-1: length_from_start=None
else:
npc_m.print_categorical_bracket('ERROR','--length-from-start argument must not less than 1 or must be -1.')
exit(2)
if length_from_end!=None:
if length_from_end<1:
if length_from_end==-1: length_from_end=None
else:
npc_m.print_categorical_bracket('ERROR','--length-from-start argument must not less than 1 or must be -1.')
exit(2)
###
##
## Command checking then doing corresponding action
# Registration
if command=='reg':
try:
f_group=ask_csv('Group').upper()
f_subject=ask_csv('Subject').upper()
while True:
f_assigned_date=ask_csv_date('Assigned Date')
f_safe_deadline=ask_csv_date('Safe Deadline')
f_optimal_deadline=ask_csv_date('Optimal Deadline')
f_minimal_deadline=ask_csv_date('Minimal Deadline')
f_due_date=ask_csv_date('Due Date')
sorting_testing=[]
if f_assigned_date!='': sorting_testing+=[f_assigned_date]
if f_safe_deadline!='': sorting_testing+=[f_safe_deadline]
if f_optimal_deadline!='': sorting_testing+=[f_optimal_deadline]
if f_minimal_deadline!='': sorting_testing+=[f_minimal_deadline]
if f_due_date!='': sorting_testing+=[f_due_date]
if sorting_testing!=sorted(sorting_testing):
npc_m.print_categorical_bracket('ERROR','Date should be sorted in order.')
continue
break
f_description=ask_csv('Description')
while True:
f_importance=ask_csv('Importance')
if f_importance not in ['-1','0','1','']:
npc_m.print_categorical_bracket('ERROR','Inputted text should be -1,0,1.')
continue
else: break
except (KeyboardInterrupt,EOFError): exit(0)
data=f_group+','+f_subject+','+f_assigned_date+','+f_safe_deadline+','+f_optimal_deadline+','+f_minimal_deadline+','+f_due_date+','+f_importance+','+f_description+'\n'
open(FILE_PATH,'a').write(data)
# Printing result using user-implementaion method
elif command=='userread':
df=sort(load_df(),sort_method)
df=df_cut(df,start_index,end_index,start_pos,end_pos,length_from_start,length_from_end)
process_then_print_df(df,date_offset)
elif command=='readdesc':
if not npc_m.is_integer_string(args[0]):
npc_m.print_categorical_bracket('ERROR','Index must be integer.')
exit(2)
index=int(args[0])
if index<0:
npc_m.print_categorical_bracket('ERROR','Index must be positive or zero integer.')
exit(2)
try: print(load_df().loc[int(args[0]),'Description'])
except KeyError:
npc_m.print_categorical_bracket('ERROR','Data is not available at specified index.')
exit(2)
else:
npc_m.print_categorical_bracket('ERROR','Unknown command \''+command+'\'.'); exit(1)
##
#!/usr/bin/env python3
# Name: Academic Todo Recording
# Description: Program helps you deal with entries of academic todo record.
# Author: NP-chaonay (Nuttapong Punpipat)
# Version: 2.1.0_alpha
# Version Note:
# - Major version: indicates of very significant changes or changes that break compatibility on some system/platforms.
# - Micro version: indicates of small changes or bug patches, or even typo revising.
# - Minor version: indicates of significant changes or features adding.
# Revised Date: 2020-08-01 08:28 (UTC)
# License: MIT License
# Programming Language: Python
# CUI/GUI Language: English
# Quality Checking: NotYet (Choose from [None,NotYet,Completed,...])
## Importing modules
import np_chaonay.main as npc_m
import re,sys,os,time,getopt,datetime
import numpy as np
import pandas as pd
import warnings
##
## User parameters
# File name (Used in DEFAULT_FILEPATH)
FILE_NAME='Todo_Academic_Record.csv'
# Default database path
DEFAULT_FILEPATH='/sdcard/Temporary/'+FILE_NAME
# Default timeweight
DEFAULT_TIMEWEIGHT=1.0
# Timeweight of subject (Undefined subject has a timeweight value as DEFAULT_TIMEWEIGHT)
TIMEWEIGHT={
# ความสำคัญสูงมาก
'I-GENERAL':10,
# วิชาที่ระบุหน่วยกิต
'SUPPMATH':2,
'PHYSICS':2,
'PHYSIC':2,
'CHEM':1.5,
'BIO':1.5,
'HE':0.5,
'MART':0.5,
'MUSIC':0.5,
'ART':0.5,
# พลศึกษาไม่ได้ระบุไว้ในคู่มือฯ ฉะนั้นกำหนดให้มีค่าเหมือน "สุขศึกษา"
'PE':0.5,
# แนะแนว น่าจะเทียบเท่า 0.5
'LIFEC':0.5,
'COUN':0.5,
# บำเพ็ญประโยชน์/ร.ด./จิตอาสาอื่น ๆ น่าจะเทียบเท่า 0.5
'HELP':0.5,
'RD':0.5,
'VOL':0.5,
# ชมรม น่าจะเทียบเท่า 0.5
'CLUB':0.5,
}
# Set columns displaying's ordering and formatting
PRINT_DF_COLS=[
['Subject','Group','Status','Importance','TimeWeight',],
['SafeDeadlineDistance','OptimalDeadlineDistance','MinimalDeadlineDistance','DueDateDistance',],
['AssignedDate','SafeDeadline','OptimalDeadline','MinimalDeadline','DueDate'],
['MaxDay','MedDay','MinDay'],
['Description'],
]
# Set default sorting method
DEFAULT_SORT_METHOD='default'
##
## Defining functions
def ask_csv(prompt_msg):
while True:
var=input(prompt_msg+': ').strip()
if ',' in var: npc_m.print_categorical_bracket('ERROR','Inputted text should not consist of comma.')
else: break
return var
def ask_csv_date(prompt_msg):
while True:
var=ask_csv(prompt_msg)
if var=='': break
elif not re.match(r'^([0-9]){6}$',var): npc_m.print_categorical_bracket('ERROR','Inputted text should use specificied date format.')
else: break
return var
def load_df():
df=pd.read_csv(FILE_PATH,header=None,names=('Group','Subject','AssignedDate','SafeDeadline','OptimalDeadline','MinimalDeadline','DueDate','Importance','MinDay','MedDay','MaxDay','Description'),dtype=DTYPE)
return df
def sort(df,sort_method):
if sort_method=='byassign-as':
tmp_df=df.copy()
tmp_df.loc[:,'AssignedDate']=df.loc[:,'AssignedDate'].astype('float')
tmp_df=tmp_df.reset_index().sort_values(['AssignedDate','index'],ascending=False,kind='mergesort',na_position='first').set_index('index')
tmp_df.index.name=None
tmp_df=df.iloc[tmp_df.index]
return tmp_df
elif sort_method=='byassign-de':
tmp_df=df.copy()
tmp_df.loc[:,'AssignedDate']=df.loc[:,'AssignedDate'].astype('float')
tmp_df=tmp_df.reset_index().sort_values(['AssignedDate','index'],ascending=True,kind='mergesort',na_position='first').set_index('index')
tmp_df.index.name=None
tmp_df=df.iloc[tmp_df.index]
return tmp_df
elif sort_method=='opti-1':
tmp_df=df.copy()
tmp_df.loc[:,'OptimalDeadline']=df.loc[:,'OptimalDeadline'].astype('float')
tmp_df.loc[:,'MinimalDeadline']=df.loc[:,'MinimalDeadline'].astype('float')
tmp_df.loc[:,'Importance']=df.loc[:,'Importance'].astype('float')
tmp_df.loc[:,'SafeDeadline']=df.loc[:,'SafeDeadline'].astype('float')
tmp_df.loc[:,'TimeWeight']=df.loc[:,'Subject'].agg(lambda name: TIMEWEIGHT.get(name,DEFAULT_TIMEWEIGHT))
tmp_df.loc[:,'DueDate']=df.loc[:,'DueDate'].astype('float')
tmp_df.loc[:,'AssignedDate']=df.loc[:,'AssignedDate'].astype('float')
tmp_df.loc[:,'MDate+ODate']=df[['MinimalDeadline','OptimalDeadline']].max(axis=1)
tmp_df.loc[:,'MaxDay+MedDay+MinDay']=df[['MaxDay','MedDay','MinDay']].max(axis=1)
tmp_df.loc[:,'MedDay+MinDay']=df[['MedDay','MinDay']].max(axis=1)
tmp_df.loc[:,'SDate+ADate+DDate']=df[['SafeDeadline','AssignedDate']].max(axis=1)
tmp_df.loc[:,'SDate+ADate+DDate']=tmp_df[['SDate+ADate+DDate','DueDate']].min(axis=1)
tmp_df.loc[:,'ADate+DDate']=df[['AssignedDate','DueDate']].min(axis=1)
tmp_df=tmp_df.reset_index().sort_values(['MDate+ODate','Importance','OptimalDeadline','TimeWeight','MaxDay+MedDay+MinDay','MedDay+MinDay','MinDay','SDate+ADate+DDate','ADate+DDate','DueDate','index'],ascending=[True,False,True,False,True,True,True,True,True,True,True],kind='mergesort',na_position='last').set_index('index')
tmp_df.index.name=None
tmp_df=df.iloc[tmp_df.index]
return tmp_df
elif sort_method=='default' or sort_method=='opti-2':
tmp_df=df.copy()
tmp_df.loc[:,'OptimalDeadline']=df.loc[:,'OptimalDeadline'].astype('float')
tmp_df.loc[:,'MinimalDeadline']=df.loc[:,'MinimalDeadline'].astype('float')
tmp_df.loc[:,'Importance']=df.loc[:,'Importance'].astype('float')
tmp_df.loc[:,'SafeDeadline']=df.loc[:,'SafeDeadline'].astype('float')
tmp_df.loc[:,'TimeWeight']=df.loc[:,'Subject'].agg(lambda name: TIMEWEIGHT.get(name,DEFAULT_TIMEWEIGHT))
tmp_df.loc[:,'DueDate']=df.loc[:,'DueDate'].astype('float')
tmp_df.loc[:,'AssignedDate']=df.loc[:,'AssignedDate'].astype('float')
tmp_df.loc[:,'MDate+ODate']=df[['MinimalDeadline','OptimalDeadline']].max(axis=1)
tmp_df.loc[:,'MaxDay+MedDay+MinDay']=df[['MaxDay','MedDay','MinDay']].max(axis=1)
tmp_df.loc[:,'MedDay+MinDay']=df[['MedDay','MinDay']].max(axis=1)
tmp_df.loc[:,'SDate+ADate+DDate']=df[['SafeDeadline','AssignedDate']].max(axis=1)
tmp_df.loc[:,'SDate+ADate+DDate']=tmp_df[['SDate+ADate+DDate','DueDate']].min(axis=1)
tmp_df.loc[:,'ADate+DDate']=df[['AssignedDate','DueDate']].min(axis=1)
tmp_df=tmp_df.reset_index().sort_values(['MDate+ODate','Importance','OptimalDeadline','TimeWeight','MaxDay+MedDay+MinDay','MedDay+MinDay','MinDay','SDate+ADate+DDate','ADate+DDate','DueDate','index'],ascending=[True,False,True,False,True,True,True,True,True,True,True],kind='mergesort',na_position='last')
tmp_df=tmp_df.sort_values(['MinimalDeadline','DueDate','index'],ascending=True,kind='mergesort',na_position='last').set_index('index')
tmp_df.index.name=None
tmp_df=df.iloc[tmp_df.index]
return tmp_df
else:
npc_m.print_categorical_bracket('ERROR','Unknown sort method \''+sort_method+'\'.')
exit(2)
def process_then_print_df(df,date_offset=0):
global current_date
tmp_df=df.copy()
current_date=time.localtime(time.time()+(24*60*60)*date_offset)
current_date=npc_m.add_lead_zero(current_date[0],2,True)[-2:]+npc_m.add_lead_zero(current_date[1],2)+npc_m.add_lead_zero(current_date[2],2)
current_date=datestr_to_date(current_date)
tmp_df['TimeWeight']=tmp_df['Subject'].agg(lambda name: TIMEWEIGHT.get(name,DEFAULT_TIMEWEIGHT))
tmp_df['SafeDeadlineDistance']=tmp_df['SafeDeadline'].agg(date_diff_func)
tmp_df['OptimalDeadlineDistance']=tmp_df['OptimalDeadline'].agg(date_diff_func)
tmp_df['MinimalDeadlineDistance']=tmp_df['MinimalDeadline'].agg(date_diff_func)
tmp_df['DueDateDistance']=tmp_df['DueDate'].agg(date_diff_func)
## STATUS
tmp_df['Status']=tmp_df[['SafeDeadline','OptimalDeadline','MinimalDeadline','DueDate']].agg(status_picker,axis=1)
##
with pd.option_context('display.max_rows', None, 'display.max_columns', None):
tmp_df=tmp_df.groupby('Importance')
for group in tmp_df.groups:
print('################ Importance:'+str(group)+' ################')
for cols in PRINT_DF_COLS:
print(tmp_df.get_group(group)[cols])
print('###############################################\n')
def df_cut(df,start_index=None,end_index=None,start_pos=None,end_pos=None,length_from_start=None,length_from_end=None):
if start_pos is None: start_pos=1
if length_from_end is None: length_from_end=0
return df.loc[start_index:end_index].iloc[start_pos-1:end_pos].iloc[-length_from_end:length_from_start]
def status_picker(series):
## Initialzation
series=tuple(map(datestr_to_date,series))
series=np.array(series)
## Find equal position / nearest position
if current_date==series[0]: pos=(0,)
elif current_date==series[1]: pos=(1,)
elif current_date==series[2]: pos=(2,)
elif current_date==series[3]: pos=(3,)
else:
upper=[]
lower=[]
lower+=[-1]
if series[0]:
if current_date>series[0]: lower+=[0]
if current_date<series[0]: upper+=[0]
if series[1]:
if current_date>series[1]: lower+=[1]
if current_date<series[1]: upper+=[1]
if series[2]:
if current_date>series[2]: lower+=[2]
if current_date<series[2]: upper+=[2]
if series[3]:
if current_date>series[3]: lower+=[3]
if current_date<series[3]: upper+=[3]
upper+=[-1]
pos=(lower[-1],upper[0])
## Find postions with duplicated value
if len(pos)==2:
if pos[0]==-1: match_date_lower=[-1]
else: match_date_lower=np.where(series==series[pos[0]])[0]
if pos[1]==-1: match_date_upper=[-1]
else: match_date_upper=np.where(series==series[pos[1]])[0]
else: match_date=np.where(series==series[pos])[0]
## Pick up corresponding message string
message=np.array(('Safe','Optimal','Minimal','Due'))
if len(pos)==2:
if pos[0]==-1 and pos[1]!=-1: return 'Before '+','.join(message[match_date_upper])+' date'
elif pos[0]!=-1 and pos[1]==-1: return 'After '+','.join(message[match_date_lower])+' date'
elif pos[0]==-1 and pos[1]==-1: return 'DeadlineDateIsNotDefined'
else: return 'Between '+','.join(message[match_date_lower])+' and '+','.join(message[match_date_upper])+' date'
else: return 'On '+','.join(message[match_date])+' date'
def datestr_to_date(datestr):
if datestr!=datestr: return None
else:
y=int(datestr[0:2])
m=int(datestr[2:4])
d=int(datestr[4:6])
return datetime.date(y,m,d)
def date_diff_func(datestr):
given_date=datestr_to_date(datestr)
if given_date:
return ( given_date-current_date ).days
else: return float('nan')
##
## Program Initialization
warnings.filterwarnings('ignore','',RuntimeWarning)
DTYPE={
'Group':'category',
'Subject':'category',
'AssignedDate':'str',
'SafeDeadline':'str',
'OptimalDeadline':'str',
'MinimalDeadline':'str',
'DueDate':'str',
'Importance':'category',
'Description':'str',
'MaxDay':'float',
'MedDay':'float',
'MinDay':'float',
}
##
## Command-line parsing
options=dict()
try: command=sys.argv[1]
except IndexError:
npc_m.print_categorical_bracket('ERROR','Command unspecified.')
exit(2)
if len(sys.argv)>2:
args=sys.argv[2:]
try: options,args=getopt.getopt(args,'',['file-path=','start-index=','end-index=','start-pos=','end-pos=','length-from-start=','length-from-end=','date-offset=','sort-method='])
except getopt.GetoptError as err:
npc_m.print_categorical_bracket('ERROR','Unrecognized or argument-needed option \''+err.opt+'\'.')
exit(2)
options=dict(options)
### Default parameters
FILE_PATH=options.get('--file-path',DEFAULT_FILEPATH)
start_index=options.get('--start-index',None)
end_index=options.get('--end-index',None)
start_pos=options.get('--start-pos',None)
end_pos=options.get('--end-pos',None)
length_from_start=options.get('--length-from-start',None)
length_from_end=options.get('--length-from-end',None)
date_offset=options.get('--date-offset',0)
sort_method=options.get('--sort-method',DEFAULT_SORT_METHOD)
### Checking typed arguments
tmp_bool_1='--start-index' in options
tmp_bool_2='--end-index' in options
tmp_bool_3='--start-pos' in options
tmp_bool_4='--end-pos' in options
tmp_bool_5='--length-from-start' in options
tmp_bool_6='--length-from-end' in options
if tmp_bool_5 and tmp_bool_6:
npc_m.print_categorical_bracket('ERROR','--length-from-start and --length-from-end cannot be specified simultaneously.')
exit(2)
tmp=(tmp_bool_1,tmp_bool_3,tmp_bool_6)
if not npc_m.is_only_one_True(tmp) and any(tmp):
npc_m.print_categorical_bracket('ERROR','--start-index, --start-pos, and --length-from-end cannot be specified simultaneously.')
exit(2)
tmp=(tmp_bool_2,tmp_bool_4,tmp_bool_5)
if not npc_m.is_only_one_True(tmp) and any(tmp):
npc_m.print_categorical_bracket('ERROR','--end-index, --end-pos, and --length-from-start cannot be specified simultaneously.')
exit(2)
### Checking string type
if start_index is None: pass
elif npc_m.is_integer_string(start_index): start_index=int(start_index)
else:
npc_m.print_categorical_bracket('ERROR','--start-index argument must be integer.')
exit(2)
if end_index is None: pass
elif npc_m.is_integer_string(end_index): end_index=int(end_index)
else:
npc_m.print_categorical_bracket('ERROR','--end-index argument must be integer.')
exit(2)
if start_pos is None: pass
elif npc_m.is_integer_string(start_pos): start_pos=int(start_pos)
else:
npc_m.print_categorical_bracket('ERROR','--start-pos argument must be integer.')
exit(2)
if end_pos is None: pass
elif npc_m.is_integer_string(end_pos): end_pos=int(end_pos)
else:
npc_m.print_categorical_bracket('ERROR','--end-pos argument must be integer.')
exit(2)
if length_from_start is None: pass
elif npc_m.is_integer_string(length_from_start): length_from_start=int(length_from_start)
else:
npc_m.print_categorical_bracket('ERROR','--length-from-start argument must be integer.')
exit(2)
if length_from_end is None: pass
elif npc_m.is_integer_string(length_from_end): length_from_end=int(length_from_end)
else:
npc_m.print_categorical_bracket('ERROR','--length-from-end argument must be integer.')
exit(2)
if date_offset==0: pass
elif npc_m.is_integer_string(date_offset): date_offset=int(date_offset)
else:
npc_m.print_categorical_bracket('ERROR','--date-offset argument must be integer.')
exit(2)
### Checking for "FILE_PATH"
if FILE_PATH=='':
npc_m.print_categorical_bracket('ERROR','--file-path argument must not be empty.')
exit(2)
### Checking values
if start_index!=None:
if start_index<0:
if start_index==-1: start_index=None
else:
npc_m.print_categorical_bracket('ERROR','--start-index argument must not less than 0 or must be -1.')
exit(2)
if end_index!=None:
if end_index<0:
if end_index==-1: end_index=None
else:
npc_m.print_categorical_bracket('ERROR','--end-index argument must not less than 0 or must be -1.')
exit(2)
if start_pos!=None:
if start_pos<1:
if start_pos==-1: start_pos=None
else:
npc_m.print_categorical_bracket('ERROR','--start-pos argument must not less than 1 or must be -1.')
exit(2)
if end_pos!=None:
if end_pos<1:
if end_pos==-1: end_pos=None
else:
npc_m.print_categorical_bracket('ERROR','--end-pos argument must not less than 1 or must be -1.')
exit(2)
if length_from_start!=None:
if length_from_start<1:
if length_from_start==-1: length_from_start=None
else:
npc_m.print_categorical_bracket('ERROR','--length-from-start argument must not less than 1 or must be -1.')
exit(2)
if length_from_end!=None:
if length_from_end<1:
if length_from_end==-1: length_from_end=None
else:
npc_m.print_categorical_bracket('ERROR','--length-from-start argument must not less than 1 or must be -1.')
exit(2)
###
##
## Command checking then doing corresponding action
# Registration
if command=='reg':
try:
f_group=ask_csv('Group').upper()
f_subject=ask_csv('Subject').upper()
while True:
while True:
f_maxday=ask_csv('Maximum doing day')
if not npc_m.is_integer_string(f_maxday) and f_maxday!='':
npc_m.print_categorical_bracket('ERROR','Quantity should be in integer or empty.')
continue
break
while True:
f_medday=ask_csv('Optimal doing day')
if not npc_m.is_integer_string(f_medday) and f_medday!='':
npc_m.print_categorical_bracket('ERROR','Quantity should be in integer or empty.')
continue
break
while True:
f_minday=ask_csv('Minimum doing day')
if not npc_m.is_integer_string(f_minday) and f_minday!='':
npc_m.print_categorical_bracket('ERROR','Quantity should be in integer or empty.')
continue
break
sorting_testing=[]
if f_minday!='': sorting_testing+=[f_minday]
if f_medday!='': sorting_testing+=[f_medday]
if f_maxday!='': sorting_testing+=[f_maxday]
tmp=np.array(sorting_testing).astype(float)
if not (tmp==np.sort(tmp)).all():
npc_m.print_categorical_bracket('ERROR','Quantities should be sorted in order.')
continue
break
while True:
f_assigned_date=ask_csv_date('Assigned Date')
f_safe_deadline=ask_csv_date('Safe Deadline')
f_optimal_deadline=ask_csv_date('Optimal Deadline')
f_minimal_deadline=ask_csv_date('Minimal Deadline')
f_due_date=ask_csv_date('Due Date')
sorting_testing=[]
if f_assigned_date!='': sorting_testing+=[f_assigned_date]
if f_safe_deadline!='': sorting_testing+=[f_safe_deadline]
if f_optimal_deadline!='': sorting_testing+=[f_optimal_deadline]
if f_minimal_deadline!='': sorting_testing+=[f_minimal_deadline]
if f_due_date!='': sorting_testing+=[f_due_date]
tmp=np.array(sorting_testing).astype(float)
if not (tmp==np.sort(tmp)).all():
npc_m.print_categorical_bracket('ERROR','Quantities should be sorted in order.')
continue
break
f_description=ask_csv('Description')
while True:
f_importance=ask_csv('Importance')
if f_importance not in ['-1','0','1','']:
npc_m.print_categorical_bracket('ERROR','Inputted text should be -1,0,1.')
continue
else: break
except (KeyboardInterrupt,EOFError): exit(0)
data=f_group+','+f_subject+','+f_assigned_date+','+f_safe_deadline+','+f_optimal_deadline+','+f_minimal_deadline+','+f_due_date+','+f_importance+','+f_minday+','+f_medday+','+f_maxday+','+f_description+'\n'
open(FILE_PATH,'a').write(data)
# Printing result using user-implementaion method
elif command=='userread':
df=sort(load_df(),sort_method)
df=df_cut(df,start_index,end_index,start_pos,end_pos,length_from_start,length_from_end)
process_then_print_df(df,date_offset)
elif command=='readdesc':
if not npc_m.is_integer_string(args[0]):
npc_m.print_categorical_bracket('ERROR','Index must be integer.')
exit(2)
index=int(args[0])
if index<0:
npc_m.print_categorical_bracket('ERROR','Index must be positive or zero integer.')
exit(2)
try: print(load_df().loc[int(args[0]),'Description'])
except KeyError:
npc_m.print_categorical_bracket('ERROR','Data is not available at specified index.')
exit(2)
else:
npc_m.print_categorical_bracket('ERROR','Unknown command \''+command+'\'.'); exit(1)
##
#!/usr/bin/env python3
# Name: Academic Todo Recording
# Description: Program helps you deal with entries of academic todo record.
# Author: NP-chaonay (Nuttapong Punpipat)
# Version: 3.6.0_stable
# Version Note:
# - Major version: File produced on different major version is not compatible
# - Minor version: Features adding
# - Micro version: Bugs fixing
# - The last entry of columns is added without major versioning changing.
# Revised Date: 2020-10-07 15:04 (UTC)
# License: MIT License
# Programming Language: Python
# CUI/GUI Language: English
# Development Stage :
# [/] Reviewing of Code
# [] Reviewing of Type and Value Checking & Error Handling
# [] Reviewing of Documentations
# [] Testing
## Importing modules
import np_chaonay.main as npc_m
import re,sys,os,time,getopt,datetime
import numpy as np
import pandas as pd
import warnings
import calendar as cal
##
## User parameters
# File name (Used in DEFAULT_FILEPATH)
FILE_NAME='Todo_Academic_Record.csv'
# Default database path
DEFAULT_FILEPATH='/sdcard/Temporary/'+FILE_NAME
# Default timeweight
DEFAULT_TIMEWEIGHT=1.0
# Timeweight of subject (Undefined subject has a timeweight value as DEFAULT_TIMEWEIGHT)
TIMEWEIGHT={
# ความสำคัญสูงมาก
'I-GENERAL':10,
# วิชาที่ระบุหน่วยกิต
'SUPPMATH':2,
'PHYSICS':2,
'PHYSIC':2,
'CHEM':1.5,
'BIO':1.5,
'HE':0.5,
'MART':0.5,
'MUSIC':0.5,
'ART':0.5,
# พลศึกษาไม่ได้ระบุไว้ในคู่มือฯ ฉะนั้นกำหนดให้มีค่าเหมือน "สุขศึกษา"
'PE':0.5,
# แนะแนว น่าจะเทียบเท่า 0.5
'LIFEC':0.5,
'COUN':0.5,
# บำเพ็ญประโยชน์/ร.ด./จิตอาสาอื่น ๆ น่าจะเทียบเท่า 0.5
'HELP':0.5,
'RD':0.5,
'VOL':0.5,
# ชมรม น่าจะเทียบเท่า 0.5
'CLUB':0.5,
}
# Set columns displaying's ordering and formatting
PRINT_DF_COLS=[
['Subject','Group','Status','Importance','TimeWeight',],
['SafeDeadlineDistance','OptimalDeadlineDistance','MinimalDeadlineDistance','DueDateDistance',],
['AssignedDate','SafeDeadline','OptimalDeadline','MinimalDeadline','DueDate'],
['MaxDay','MedDay','MinDay','IsHeavy'],
['Description'],
['Tags'],
]
# Default sorting method
DEFAULT_SORT_METHOD='opti-2'
# Default grouping settings on dataframe printing
DEFAULT_PRINTING_GROUPING_ENABLED=True
DEFAULT_PRINTING_GROUPING_BY='Importance'
##
## Defining functions
def ask_csv(prompt_msg):
while True:
var=input(prompt_msg+': ').strip()
if ',' in var: npc_m.print_categorical_bracket('ERROR','Inputted text should not consist of comma.')
else: break
return var
def ask_csv_date(prompt_msg):
while True:
var=ask_csv(prompt_msg)
if var=='': break
elif not re.match(r'^([0-9]){6}$',var): npc_m.print_categorical_bracket('ERROR','Inputted text should use specificied date format.')
else: break
return var
def load_df():
df=pd.read_csv(FILE_PATH,header=None,names=('Group','Subject','AssignedDate','SafeDeadline','OptimalDeadline','MinimalDeadline','DueDate','Importance','IsHeavy','MinDay','MedDay','MaxDay','Description','Tags'),dtype=DTYPE)
return df
def sort(df,sort_method):
if sort_method=='byassign-as':
tmp_df=df.copy()
tmp_df.loc[:,'AssignedDate']=df.loc[:,'AssignedDate'].astype('float')
tmp_df=tmp_df.reset_index().sort_values(['AssignedDate','index'],ascending=False,kind='mergesort',na_position='first').set_index('index')
tmp_df.index.name=None
tmp_df=df.loc[tmp_df.index]
return tmp_df
elif sort_method=='byassign-de':
tmp_df=df.copy()
tmp_df.loc[:,'AssignedDate']=df.loc[:,'AssignedDate'].astype('float')
tmp_df=tmp_df.reset_index().sort_values(['AssignedDate','index'],ascending=True,kind='mergesort',na_position='first').set_index('index')
tmp_df.index.name=None
tmp_df=df.loc[tmp_df.index]
return tmp_df
elif sort_method=='opti-1':
tmp_df=df.copy()
tmp_df.loc[:,'OptimalDeadline']=df.loc[:,'OptimalDeadline'].astype('float')
tmp_df.loc[:,'MinimalDeadline']=df.loc[:,'MinimalDeadline'].astype('float')
tmp_df.loc[:,'Importance']=df.loc[:,'Importance'].astype('float')
tmp_df.loc[:,'SafeDeadline']=df.loc[:,'SafeDeadline'].astype('float')
tmp_df.loc[:,'TimeWeight']=df.loc[:,'Subject'].agg(lambda name: TIMEWEIGHT.get(name,DEFAULT_TIMEWEIGHT))
tmp_df.loc[:,'DueDate']=df.loc[:,'DueDate'].astype('float')
tmp_df.loc[:,'AssignedDate']=df.loc[:,'AssignedDate'].astype('float')
tmp_df.loc[:,'MDate+ODate']=df[['MinimalDeadline','OptimalDeadline']].max(axis=1)
tmp_df.loc[:,'MaxDay+MedDay+MinDay']=df[['MaxDay','MedDay','MinDay']].max(axis=1)
tmp_df.loc[:,'MedDay+MinDay']=df[['MedDay','MinDay']].max(axis=1)
tmp_df.loc[:,'SDate+ADate+DDate']=df[['SafeDeadline','AssignedDate']].max(axis=1)
tmp_df.loc[:,'SDate+ADate+DDate']=tmp_df[['SDate+ADate+DDate','DueDate']].min(axis=1)
tmp_df.loc[:,'ADate+DDate']=df[['AssignedDate','DueDate']].min(axis=1)
tmp_df=tmp_df.reset_index()
### Sorting layers
tmp_df=tmp_df.sort_values(['OptimalDeadline','TimeWeight','MaxDay+MedDay+MinDay','MedDay+MinDay','MinDay','SDate+ADate+DDate','ADate+DDate','DueDate','index'],ascending=[True,False,True,True,True,True,True,True,True],kind='mergesort',na_position='last')
tmp_df=tmp_df.sort_values(['IsHeavy','index'],ascending=[False,True],kind='mergesort',na_position='first')
tmp_df=tmp_df.sort_values(['MDate+ODate','Importance','index'],ascending=[True,False,True],kind='mergesort',na_position='first')
###
tmp_df=tmp_df.set_index('index')
tmp_df.index.name=None
tmp_df=df.loc[tmp_df.index]
return tmp_df
elif sort_method=='opti-2':
tmp_df=df.copy()
tmp_df.loc[:,'OptimalDeadline']=df.loc[:,'OptimalDeadline'].astype('float')
tmp_df.loc[:,'MinimalDeadline']=df.loc[:,'MinimalDeadline'].astype('float')
tmp_df.loc[:,'Importance']=df.loc[:,'Importance'].astype('float')
tmp_df.loc[:,'SafeDeadline']=df.loc[:,'SafeDeadline'].astype('float')
tmp_df.loc[:,'TimeWeight']=df.loc[:,'Subject'].agg(lambda name: TIMEWEIGHT.get(name,DEFAULT_TIMEWEIGHT))
tmp_df.loc[:,'DueDate']=df.loc[:,'DueDate'].astype('float')
tmp_df.loc[:,'AssignedDate']=df.loc[:,'AssignedDate'].astype('float')
tmp_df.loc[:,'MDate+ODate']=df[['MinimalDeadline','OptimalDeadline']].max(axis=1)
tmp_df.loc[:,'MaxDay+MedDay+MinDay']=df[['MaxDay','MedDay','MinDay']].max(axis=1)
tmp_df.loc[:,'MedDay+MinDay']=df[['MedDay','MinDay']].max(axis=1)
tmp_df.loc[:,'SDate+ADate+DDate']=df[['SafeDeadline','AssignedDate']].max(axis=1)
tmp_df.loc[:,'SDate+ADate+DDate']=tmp_df[['SDate+ADate+DDate','DueDate']].min(axis=1)
tmp_df.loc[:,'ADate+DDate']=df[['AssignedDate','DueDate']].min(axis=1)
tmp_df=tmp_df.reset_index()
### Sorting layers
tmp_df=tmp_df.sort_values(['OptimalDeadline','TimeWeight','MaxDay+MedDay+MinDay','MedDay+MinDay','MinDay','SDate+ADate+DDate','ADate+DDate','DueDate','index'],ascending=[True,False,True,True,True,True,True,True,True],kind='mergesort',na_position='last')
tmp_df=tmp_df.sort_values(['IsHeavy','index'],ascending=[False,True],kind='mergesort',na_position='first')
tmp_df=tmp_df.sort_values(['MDate+ODate','Importance','index'],ascending=[True,False,True],kind='mergesort',na_position='first')
tmp_df=tmp_df.sort_values(['MinimalDeadline','DueDate','index'],ascending=True,kind='mergesort',na_position='last')
###
tmp_df=tmp_df.set_index('index')
tmp_df.index.name=None
tmp_df=df.loc[tmp_df.index]
return tmp_df
else:
npc_m.print_categorical_bracket('ERROR','Unknown sort method \''+sort_method+'\'.')
exit(2)
def df_main_process(df,date_offset):
global current_date
tmp_df=df.copy()
current_date=time.localtime(time.time()+(24*60*60)*date_offset)
current_date=npc_m.add_lead_zero(current_date[0],2,True)[-2:]+npc_m.add_lead_zero(current_date[1],2)+npc_m.add_lead_zero(current_date[2],2)
current_date=datestr_to_date(current_date)
tmp_df['TimeWeight']=tmp_df['Subject'].agg(lambda name: TIMEWEIGHT.get(name,DEFAULT_TIMEWEIGHT))
tmp_df['SafeDeadlineDistance']=tmp_df['SafeDeadline'].agg(date_diff_func)
tmp_df['OptimalDeadlineDistance']=tmp_df['OptimalDeadline'].agg(date_diff_func)
tmp_df['MinimalDeadlineDistance']=tmp_df['MinimalDeadline'].agg(date_diff_func)
tmp_df['DueDateDistance']=tmp_df['DueDate'].agg(date_diff_func)
## STATUS
tmp_df['Status']=tmp_df[['SafeDeadline','OptimalDeadline','MinimalDeadline','DueDate']].agg(status_picker,axis=1)
##
return tmp_df
def df_cut(df,start_index,end_index,start_pos,end_pos,length_from_start,length_from_end):
if start_pos is None: start_pos=1
if length_from_end is None: length_from_end=0
return df.loc[start_index:end_index].iloc[start_pos-1:end_pos].iloc[-length_from_end:length_from_start]
def status_picker(series):
## Initialzation
series=tuple(map(datestr_to_date,series))
series=np.array(series)
## Find equal position / nearest position
if current_date==series[0]: pos=(0,)
elif current_date==series[1]: pos=(1,)
elif current_date==series[2]: pos=(2,)
elif current_date==series[3]: pos=(3,)
else:
upper=[]
lower=[]
lower+=[-1]
if series[0]:
if current_date>series[0]: lower+=[0]
if current_date<series[0]: upper+=[0]
if series[1]:
if current_date>series[1]: lower+=[1]
if current_date<series[1]: upper+=[1]
if series[2]:
if current_date>series[2]: lower+=[2]
if current_date<series[2]: upper+=[2]
if series[3]:
if current_date>series[3]: lower+=[3]
if current_date<series[3]: upper+=[3]
upper+=[-1]
pos=(lower[-1],upper[0])
## Find postions with duplicated value
if len(pos)==2:
if pos[0]==-1: match_date_lower=[-1]
else: match_date_lower=np.where(series==series[pos[0]])[0]
if pos[1]==-1: match_date_upper=[-1]
else: match_date_upper=np.where(series==series[pos[1]])[0]
else: match_date=np.where(series==series[pos])[0]
## Pick up corresponding message string
message=np.array(('Safe','Optimal','Minimal','Due'))
if len(pos)==2:
if pos[0]==-1 and pos[1]!=-1: return 'Before '+','.join(message[match_date_upper])+' date'
elif pos[0]!=-1 and pos[1]==-1: return 'After '+','.join(message[match_date_lower])+' date'
elif pos[0]==-1 and pos[1]==-1: return 'DeadlineDateIsNotDefined'
else: return 'Between '+','.join(message[match_date_lower])+' and '+','.join(message[match_date_upper])+' date'
else: return 'On '+','.join(message[match_date])+' date'
def datestr_to_date(datestr):
if datestr!=datestr: return None
else:
y=int(datestr[0:2])
m=int(datestr[2:4])
d=int(datestr[4:6])
return datetime.date(y,m,d)
def date_diff_func(datestr):
given_date=datestr_to_date(datestr)
if given_date:
return ( given_date-current_date ).days
else: return float('nan')
def print_df(df,grouping,grouping_by):
with pd.option_context('display.max_rows', None, 'display.max_columns', None):
if grouping:
df=df.groupby(grouping_by)
for group in df.groups:
print('################ '+grouping_by+':'+str(group)+' ################')
for cols in PRINT_DF_COLS:
print(df.get_group(group)[cols])
print('###############################################\n')
else:
for cols in PRINT_DF_COLS: print(df[cols])
def short_header_print_1(task):
print('- ',task.name,' / ',task['Subject'],' / ',task['Tags'],' / ',task['Description'],sep='')
def twomoncal(time_pos=None):
if time_pos: ltc=time_pos
else:
ltc=time.localtime()
ltc=ltc.tm_year,ltc.tm_mon
ltc_=[ltc[0],ltc[1]+1]
if ltc_[1]==13:
ltc_[0]=ltc_[0]+1
ltc_[1]=1
sep='-'*20+'\n'
print(sep+cal.month(*ltc)+sep+cal.month(*ltc_)+sep,end='')
##
## Program Initialization
warnings.filterwarnings('ignore','',RuntimeWarning)
DTYPE={
'Group':'category',
'Subject':'category',
'AssignedDate':'str',
'SafeDeadline':'str',
'OptimalDeadline':'str',
'MinimalDeadline':'str',
'DueDate':'str',
'Importance':'category',
'IsHeavy':'float',
'Description':'str',
'MaxDay':'float',
'MedDay':'float',
'MinDay':'float',
'Tags':'str',
}
##
## Command-line parsing
options=dict()
args=sys.argv[1:]
try: options,args=getopt.getopt(args,'',['file-path=','start=','end=','length-from-start=','length-from-end=','start-sorted-index=','end-sorted-index=','start-sorted-pos=','end-sorted-pos=','length-from-sorted-start=','length-from-sorted-end=','date-offset=','sort-method=','printing-grouping-enabled=','printing-grouping-by='])
except getopt.GetoptError as err:
npc_m.print_categorical_bracket('ERROR','Unrecognized or argument-needed option \''+err.opt+'\'.')
exit(2)
try: command=args[0]
except IndexError:
npc_m.print_categorical_bracket('ERROR','Command unspecified.')
exit(2)
options=dict(options)
### Default parameters
FILE_PATH=options.get('--file-path',DEFAULT_FILEPATH)
start=options.get('--start',None)
end=options.get('--end',None)
length_from_start=options.get('--length-from-start',None)
length_from_end=options.get('--length-from-end',None)
start_sorted_index=options.get('--start-sorted-index',None)
end_sorted_index=options.get('--end-sorted-index',None)
start_sorted_pos=options.get('--start-sorted-pos',None)
end_sorted_pos=options.get('--end-sorted-pos',None)
length_from_sorted_start=options.get('--length-from-sorted-start',None)
length_from_sorted_end=options.get('--length-from-sorted-end',None)
date_offset=options.get('--date-offset',0)
sort_method=options.get('--sort-method',DEFAULT_SORT_METHOD)
printing_grouping_enabled=options.get('--printing-grouping-enabled',DEFAULT_PRINTING_GROUPING_ENABLED)
printing_grouping_by=options.get('--printing-grouping-by',DEFAULT_PRINTING_GROUPING_BY)
### Checking compatibility of arguments
tmp_bool_1='--start-sorted-index' in options
tmp_bool_2='--end-sorted-index' in options
tmp_bool_3='--start-sorted-pos' in options
tmp_bool_4='--end-sorted-pos' in options
tmp_bool_5='--length-from-sorted-start' in options
tmp_bool_6='--length-from-sorted-end' in options
tmp_bool_7='--start' in options
tmp_bool_8='--end' in options
tmp_bool_9='--length-from-start' in options
tmp_bool_10='--length-from-end' in options
if tmp_bool_5 and tmp_bool_6:
npc_m.print_categorical_bracket('ERROR','--length-from-sorted-start and --length-from-sorted-end cannot be specified simultaneously.')
exit(2)
tmp=(tmp_bool_1,tmp_bool_3,tmp_bool_6)
if not npc_m.is_only_one_True(tmp) and any(tmp):
npc_m.print_categorical_bracket('ERROR','--start-sorted-index, --start-sorted-pos, and --length-from-sorted-end cannot be specified simultaneously.')
exit(2)
tmp=(tmp_bool_2,tmp_bool_4,tmp_bool_5)
if not npc_m.is_only_one_True(tmp) and any(tmp):
npc_m.print_categorical_bracket('ERROR','--end-sorted-index, --end-sorted-pos, and --length-from-sorted-start cannot be specified simultaneously.')
exit(2)
if tmp_bool_9 and tmp_bool_10:
npc_m.print_categorical_bracket('ERROR','--length-from-start and --length-from-end cannot be specified simultaneously.')
exit(2)
if tmp_bool_7 and tmp_bool_10:
npc_m.print_categorical_bracket('ERROR','--start and --length-from-end cannot be specified simultaneously.')
exit(2)
if tmp_bool_8 and tmp_bool_9:
npc_m.print_categorical_bracket('ERROR','--end and --length-from-start cannot be specified simultaneously.')
exit(2)
### Checking string type
if start_sorted_index is None: pass
elif npc_m.is_integer_string(start_sorted_index): start_sorted_index=int(start_sorted_index)
else:
npc_m.print_categorical_bracket('ERROR','--start-sorted-index argument must be integer.')
exit(2)
if end_sorted_index is None: pass
elif npc_m.is_integer_string(end_sorted_index): end_sorted_index=int(end_sorted_index)
else:
npc_m.print_categorical_bracket('ERROR','--end-sorted-index argument must be integer.')
exit(2)
if start_sorted_pos is None: pass
elif npc_m.is_integer_string(start_sorted_pos): start_sorted_pos=int(start_sorted_pos)
else:
npc_m.print_categorical_bracket('ERROR','--start-sorted-pos argument must be integer.')
exit(2)
if end_sorted_pos is None: pass
elif npc_m.is_integer_string(end_sorted_pos): end_sorted_pos=int(end_sorted_pos)
else:
npc_m.print_categorical_bracket('ERROR','--end-sorted-pos argument must be integer.')
exit(2)
if length_from_sorted_start is None: pass
elif npc_m.is_integer_string(length_from_sorted_start): length_from_sorted_start=int(length_from_sorted_start)
else:
npc_m.print_categorical_bracket('ERROR','--length-from-sorted-start argument must be integer.')
exit(2)
if length_from_sorted_end is None: pass
elif npc_m.is_integer_string(length_from_sorted_end): length_from_sorted_end=int(length_from_sorted_end)
else:
npc_m.print_categorical_bracket('ERROR','--length-from-sorted-end argument must be integer.')
exit(2)
if date_offset==0: pass
elif npc_m.is_integer_string(date_offset): date_offset=int(date_offset)
else:
npc_m.print_categorical_bracket('ERROR','--date-offset argument must be integer.')
exit(2)
if start is None: pass
elif npc_m.is_integer_string(start): start=int(start)
else:
npc_m.print_categorical_bracket('ERROR','--start argument must be integer.')
exit(2)
if end is None: pass
elif npc_m.is_integer_string(end): end=int(end)
else:
npc_m.print_categorical_bracket('ERROR','--end argument must be integer.')
exit(2)
if length_from_start is None: pass
elif npc_m.is_integer_string(length_from_start): length_from_start=int(length_from_start)
else:
npc_m.print_categorical_bracket('ERROR','--length-from-start argument must be integer.')
exit(2)
if length_from_end is None: pass
elif npc_m.is_integer_string(length_from_end): length_from_start=int(length_from_end)
else:
npc_m.print_categorical_bracket('ERROR','--length-from-end argument must be integer.')
exit(2)
### Checking values
if FILE_PATH=='':
npc_m.print_categorical_bracket('ERROR','--file-path argument must not be empty.')
exit(2)
#
if start_sorted_index!=None:
if start_sorted_index<0:
if start_sorted_index==-1: start_sorted_index=None
else:
npc_m.print_categorical_bracket('ERROR','--start-sorted-index argument must not less than 0 or must be -1.')
exit(2)
if end_sorted_index!=None:
if end_sorted_index<0:
if end_sorted_index==-1: end_sorted_index=None
else:
npc_m.print_categorical_bracket('ERROR','--end-sorted-index argument must not less than 0 or must be -1.')
exit(2)
if start_sorted_pos!=None:
if start_sorted_pos<1:
if start_sorted_pos==-1: start_sorted_pos=None
else:
npc_m.print_categorical_bracket('ERROR','--start-sorted-pos argument must not less than 1 or must be -1.')
exit(2)
if end_sorted_pos!=None:
if end_sorted_pos<1:
if end_sorted_pos==-1: end_sorted_pos=None
else:
npc_m.print_categorical_bracket('ERROR','--end-sorted-pos argument must not less than 1 or must be -1.')
exit(2)
if length_from_sorted_start!=None:
if length_from_sorted_start<1:
if length_from_sorted_start==-1: length_from_sorted_start=None
else:
npc_m.print_categorical_bracket('ERROR','--length-from-sorted-start argument must not less than 1 or must be -1.')
exit(2)
if length_from_sorted_end!=None:
if length_from_sorted_end<1:
if length_from_sorted_end==-1: length_from_sorted_end=None
else:
npc_m.print_categorical_bracket('ERROR','--length-from-sorted-start argument must not less than 1 or must be -1.')
exit(2)
if start!=None:
if start<0:
if start==-1: start=None
else:
npc_m.print_categorical_bracket('ERROR','--start argument must not less than 0 or must be -1.')
exit(2)
if end!=None:
if end<0:
if end==-1: end=None
else:
npc_m.print_categorical_bracket('ERROR','--end argument must not less than 0 or must be -1.')
exit(2)
if length_from_start!=None:
if length_from_start<1:
if length_from_start==-1: length_from_start=None
else:
npc_m.print_categorical_bracket('ERROR','--length-from-start argument must not less than 1 or must be -1.')
exit(2)
if length_from_end!=None:
if length_from_end<1:
if length_from_end==-1: length_from_end=None
else:
npc_m.print_categorical_bracket('ERROR','--length-from-end argument must not less than 1 or must be -1.')
exit(2)
#
if type(printing_grouping_enabled) is not bool:
try: printing_grouping_enabled=npc_m.str_to_bool(printing_grouping_enabled)
except ValueError:
npc_m.print_categorical_bracket('ERROR','--printing-grouping-enabled argument must be boolean-transformable string; for reference, see documentation on \'np_chaonay.main.str_to_bool\'.')
exit(2)
###
##
## Command checking then doing corresponding action
# Registration
if command=='reg':
try:
f_group=ask_csv('Group').upper()
f_subject=ask_csv('Subject').upper()
twomoncal()
while True:
while True:
f_maxday=ask_csv('Maximum doing day')
if not npc_m.is_integer_string(f_maxday) and f_maxday!='':
npc_m.print_categorical_bracket('ERROR','Quantity should be in integer or empty.')
continue
break
while True:
f_medday=ask_csv('Optimal doing day')
if not npc_m.is_integer_string(f_medday) and f_medday!='':
npc_m.print_categorical_bracket('ERROR','Quantity should be in integer or empty.')
continue
break
while True:
f_minday=ask_csv('Minimum doing day')
if not npc_m.is_integer_string(f_minday) and f_minday!='':
npc_m.print_categorical_bracket('ERROR','Quantity should be in integer or empty.')
continue
break
sorting_testing=[]
if f_minday!='': sorting_testing+=[f_minday]
if f_medday!='': sorting_testing+=[f_medday]
if f_maxday!='': sorting_testing+=[f_maxday]
tmp=np.array(sorting_testing).astype(float)
if not (tmp==np.sort(tmp)).all():
npc_m.print_categorical_bracket('ERROR','Quantities should be sorted in order.')
continue
break
while True:
f_assigned_date=ask_csv_date('Assigned Date')
f_safe_deadline=ask_csv_date('Safe Deadline')
f_optimal_deadline=ask_csv_date('Optimal Deadline')
f_minimal_deadline=ask_csv_date('Minimal Deadline')
f_due_date=ask_csv_date('Due Date')
sorting_testing=[]
if f_assigned_date!='': sorting_testing+=[f_assigned_date]
if f_safe_deadline!='': sorting_testing+=[f_safe_deadline]
if f_optimal_deadline!='': sorting_testing+=[f_optimal_deadline]
if f_minimal_deadline!='': sorting_testing+=[f_minimal_deadline]
if f_due_date!='': sorting_testing+=[f_due_date]
tmp=np.array(sorting_testing).astype(float)
if not (tmp==np.sort(tmp)).all():
npc_m.print_categorical_bracket('ERROR','Quantities should be sorted in order.')
continue
break
f_description=ask_csv('Description')
f_tags=ask_csv('Tags')
while True:
f_importance=ask_csv('Importance')
if f_importance not in ['-1','0','1','']:
npc_m.print_categorical_bracket('ERROR','Inputted text should be -1,0,1, or empty.')
continue
else: break
while True:
f_isheavy=ask_csv('IsHeavyDoing')
if f_isheavy not in ['-2','-1','0','1','2','']:
npc_m.print_categorical_bracket('ERROR','Inputted text should be integer of [-2,2] or empty.')
continue
else: break
except (KeyboardInterrupt,EOFError): exit(0)
data=f_group+','+f_subject+','+f_assigned_date+','+f_safe_deadline+','+f_optimal_deadline+','+f_minimal_deadline+','+f_due_date+','+f_importance+','+f_isheavy+','+f_minday+','+f_medday+','+f_maxday+','+f_description+','+f_tags+'\n'
open(FILE_PATH,'a').write(data)
# Printing result using user-implementaion method
elif command=='read':
df=load_df()
df=df_cut(df,start,end,None,None,length_from_start,length_from_end)
df=sort(df,sort_method)
df=df_cut(df,start_sorted_index,end_sorted_index,start_sorted_pos,end_sorted_pos,length_from_sorted_start,length_from_sorted_end)
df=df_main_process(df,date_offset)
print_df(df,printing_grouping_enabled,printing_grouping_by)
# Printing description for specified index or all
elif command=='readdesc':
if args[1:]:
if not npc_m.is_integer_string(args[1]):
npc_m.print_categorical_bracket('ERROR','Index must be integer.')
exit(2)
index=int(args[1])
if index<0:
npc_m.print_categorical_bracket('ERROR','Index must be positive or zero integer.')
exit(2)
try: print(load_df().loc[index,'Description'])
except KeyError:
npc_m.print_categorical_bracket('ERROR','Data is not available at specified index.')
exit(1)
else:
print(load_df().loc[:,'Description'])
# Load and process df and enter debugging console
elif command=='debug':
import code
df=load_df()
df=df_cut(df,start,end,None,None,length_from_start,length_from_end)
df=sort(df,sort_method)
df=df_cut(df,start_sorted_index,end_sorted_index,start_sorted_pos,end_sorted_pos,length_from_sorted_start,length_from_sorted_end)
df=df_main_process(df,date_offset)
code.interact(banner='[Todo_Academic_Record] Entering to Python interactive shell for program debugging.'+'\n'+' '*23+'\'df\' variable is the processed-dataframe for printing using \'print_df\' function.',local=locals(),exitmsg='[Todo_Academic_Record] Debugging console is ended.')
# Print quickly-understandable status
elif command=='status':
print('(Print using the format \'Index / Subject / Tags / Description\')')
df=load_df()
df=df_cut(df,start,end,None,None,length_from_start,length_from_end)
df=sort(df,sort_method)
df=df_cut(df,start_sorted_index,end_sorted_index,start_sorted_pos,end_sorted_pos,length_from_sorted_start,length_from_sorted_end)
df=df_main_process(df,date_offset)
## Checking for tomorrow due tasks
print('\n[Due tomorrow]')
tmp_df=df['DueDateDistance']==1
tmp_df=df[tmp_df]
if tmp_df.empty:
print('< No any tasks matched the filters >')
else:
for i in range(len(tmp_df)):
task=tmp_df.iloc[i]
short_header_print_1(task)
## Checking for today due tasks
print('\n[Due today]')
tmp_df=df['DueDateDistance']==0
tmp_df=df[tmp_df]
if tmp_df.empty:
print('< No any tasks matched the filters >')
else:
for i in range(len(tmp_df)):
task=tmp_df.iloc[i]
short_header_print_1(task)
## Checking for yesterday due tasks
print('\n[Due yesterday]')
tmp_df=df['DueDateDistance']==-1
tmp_df=df[tmp_df]
if tmp_df.empty:
print('< No any tasks matched the filters >')
else:
for i in range(len(tmp_df)):
task=tmp_df.iloc[i]
short_header_print_1(task)
## Checking for nearest weekday (if Friday, including next weekday) due tasks
print('\n[Due in nearest weekday (if Friday, including next weekday)]')
tmp=time.localtime(time.time()+24*60*60*date_offset).tm_wday
if tmp in [5,6]:
date_range=np.array((1,5))+(6-tmp)
elif tmp in [0,1,2,3]:
date_range=np.array((0,(4-tmp)))
else:
date_range=np.array((0,8))
upper_mask=df['DueDateDistance']>=date_range[0]
lower_mask=df['DueDateDistance']<=date_range[1]
tmp_df=df[upper_mask&lower_mask]
if tmp_df.empty:
print('< No any tasks matched the filters >')
else:
for i in range(len(tmp_df)):
task=tmp_df.iloc[i]
short_header_print_1(task)
## Checking for tomorrow minimal-deadline tasks
print('\n[Minimal-Deadline tomorrow]')
tmp_df=df['MinimalDeadlineDistance']==1
tmp_df=df[tmp_df]
if tmp_df.empty:
print('< No any tasks matched the filters >')
else:
for i in range(len(tmp_df)):
task=tmp_df.iloc[i]
short_header_print_1(task)
## Checking for today minimal-deadline tasks
print('\n[Minimal-Deadline today]')
tmp_df=df['MinimalDeadlineDistance']==0
tmp_df=df[tmp_df]
if tmp_df.empty:
print('< No any tasks matched the filters >')
else:
for i in range(len(tmp_df)):
task=tmp_df.iloc[i]
short_header_print_1(task)
## Checking for yesterday minimal-deadline tasks
print('\n[Minimal-Deadline yesterday]')
tmp_df=df['MinimalDeadlineDistance']==-1
tmp_df=df[tmp_df]
if tmp_df.empty:
print('< No any tasks matched the filters >')
else:
for i in range(len(tmp_df)):
task=tmp_df.iloc[i]
short_header_print_1(task)
## Checking for nearest weekday (if Friday, including next weekday) minimal-deadline tasks
print('\n[Minimal-Deadline in nearest weekday (if Friday, including next weekday)]')
tmp=time.localtime(time.time()+24*60*60*date_offset).tm_wday
if tmp in [5,6]:
date_range=np.array((1,5))+(6-tmp)
elif tmp in [0,1,2,3]:
date_range=np.array((0,(4-tmp)))
else:
date_range=np.array((0,8))
upper_mask=df['MinimalDeadlineDistance']>=date_range[0]
lower_mask=df['MinimalDeadlineDistance']<=date_range[1]
tmp_df=df[upper_mask&lower_mask]
if tmp_df.empty:
print('< No any tasks matched the filters >')
else:
for i in range(len(tmp_df)):
task=tmp_df.iloc[i]
short_header_print_1(task)
## Checking for tomorrow optimal-deadline tasks
print('\n[Optimal-Deadline tomorrow]')
tmp_df=df['OptimalDeadlineDistance']==1
tmp_df=df[tmp_df]
if tmp_df.empty:
print('< No any tasks matched the filters >')
else:
for i in range(len(tmp_df)):
task=tmp_df.iloc[i]
short_header_print_1(task)
## Checking for today optimal-deadline tasks
print('\n[Optimal-Deadline today]')
tmp_df=df['OptimalDeadlineDistance']==0
tmp_df=df[tmp_df]
if tmp_df.empty:
print('< No any tasks matched the filters >')
else:
for i in range(len(tmp_df)):
task=tmp_df.iloc[i]
short_header_print_1(task)
## Checking for yesterday optimal-deadline tasks
print('\n[Optimal-Deadline yesterday]')
tmp_df=df['OptimalDeadlineDistance']==-1
tmp_df=df[tmp_df]
if tmp_df.empty:
print('< No any tasks matched the filters >')
else:
for i in range(len(tmp_df)):
task=tmp_df.iloc[i]
short_header_print_1(task)
## Checking for nearest weekday (if Friday, including next weekday) optimal-deadline tasks
print('\n[Optimal-Deadline in nearest weekday (if Friday, including next weekday)]')
tmp=time.localtime(time.time()+24*60*60*date_offset).tm_wday
if tmp in [5,6]:
date_range=np.array((1,5))+(6-tmp)
elif tmp in [0,1,2,3]:
date_range=np.array((0,(4-tmp)))
else:
date_range=np.array((0,8))
upper_mask=df['OptimalDeadlineDistance']>=date_range[0]
lower_mask=df['OptimalDeadlineDistance']<=date_range[1]
tmp_df=df[upper_mask&lower_mask]
if tmp_df.empty:
print('< No any tasks matched the filters >')
else:
for i in range(len(tmp_df)):
task=tmp_df.iloc[i]
short_header_print_1(task)
elif command=='readone':
if args[1:]:
if not npc_m.is_integer_string(args[1]):
npc_m.print_categorical_bracket('ERROR','Index must be integer.')
exit(2)
index=int(args[1])
if index<0:
npc_m.print_categorical_bracket('ERROR','Index must be positive or zero integer.')
exit(2)
try:
df=df_main_process(load_df(),date_offset)
print(df.loc[index])
except KeyError:
npc_m.print_categorical_bracket('ERROR','Data is not available at specified index.')
exit(1)
else:
npc_m.print_categorical_bracket('ERROR','Index must be specified.')
exit(2)
elif command=='shownodue':
df=load_df()
df=df_cut(df,start,end,None,None,length_from_start,length_from_end)
df=sort(df,sort_method)
df=df_cut(df,start_sorted_index,end_sorted_index,start_sorted_pos,end_sorted_pos,length_from_sorted_start,length_from_sorted_end)
df=df_main_process(df,date_offset)
## Checking for no due date tasks
print('[No due date]')
tmp_df=df['DueDate'].isna()
tmp_df=df[tmp_df]
if tmp_df.empty:
print('< No any tasks matched the filters >')
else:
for i in range(len(tmp_df)):
task=tmp_df.iloc[i]
short_header_print_1(task)
else:
npc_m.print_categorical_bracket('ERROR','Unknown command \''+command+'\'.'); exit(2)
##
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment