Last active
October 7, 2020 15:05
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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) | |
## |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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) | |
## |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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) | |
## |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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