AnalogueLife

Analogue witterings…

ToDo App completed

As it stands the ToDo app is functional.

Full C.R.U.D operations can be performed, with relevant Error checking performed where required. Designed to be a Terminal based app with a bit of bling added in the form of colour.

#!/usr/bin/env python

# ToDo terminal app
import csv
from csv import DictReader
import pyfiglet
from colorist import rgb, Color, Effect, ColorRGB
import datetime
from dateutil.parser import parse
#from dateutil.tz import *

blue = ColorRGB(51, 255, 255)
red = ColorRGB(255,0,0)
green = ColorRGB(128,255,0)
yellow = ColorRGB(255,255,0)

def add_todo():
csv_file = 'todos.csv'
with open(csv_file, 'r', newline='', encoding='utf-8') as f:
data = DictReader(f)
id = []
for col in data:
id.append(col ['ID'])
last_id = int(id[-1])

next_id = str(last_id+1)
print(f'Next ID: {next_id}')
status = input('Enter a \'Status\' (/, x, . or leave empty): ')
priority = input('Enter a \'Priority\' (A, B, C or leave empty): ')
create_on = datetime.datetime.now().strftime('%Y-%m-%d')
while True:
desc = input('Enter a Description: ')
if len(desc) <= 60:
break
else:
print(f'{red}Max: 60 characters allowed{red.OFF}')
while True:
project = input('Enter \'Project\' (title or leave empty): ')
if len(project) <= 12:
break
else:
print(f'{red}Max: 12 characters allowed{red.OFF}')
while True:
context = input('Enter \'@Context\' or leave empty: ')
if len(context) <= 12:
break
else:
print(f'{red}Max: 12 characters allowed{red.OFF}')
due_date = parse(input('Format: YYYY-mm-dd: '))

row = [next_id, status, priority, create_on, desc, project, context, due_date]
try:
with open(csv_file, 'a', newline='', encoding='utf-8') as csv_file:
writer = csv.writer(csv_file)
writer.writerow(row)
except FileNotFoundError:
print(f'File {csv_file} not found.!')
except csv.Error as e:
print(f' An error occured while appending to {csv_file}: {e}')
view_all_todos()

def delete_todo():
task = []
with open('todos.csv', 'r', newline='') as f:
deleterow = int(input('\t >> Which \'ToDo\' do you want to delete?: '))
data = csv.reader(f)
Found = False
for row in data:
if row[0] == str(deleterow):
Found = True
print(f'\t{green} >> ToDo {Effect.BOLD}#{deleterow}{Effect.BOLD_OFF} Deleted!{green.OFF}')
else:
task.append(row)
if Found == False:
print(f'\t{red} >> ToDo not found!{red.OFF}')
else:
with open('todos.csv','w+', newline='') as updated:
deleted = csv.writer(updated)
deleted.writerows(task)
updated.seek(0)
data = csv.reader(updated)
view_all_todos()

def status_todo():
with open('todos.csv', 'r', newline='', encoding='utf-8') as f:
editrow = int(input('\t >> Which ToDo \'Status\' do you want to edit?: '))
data = csv.reader(f)
completed = []
Found = False
for row in data:
if row[0] == str(editrow):
Found = True
status = ['x', '/', '.', '']
row[1] = input('\t >> Change Status (x, /, . or space ): ').lower()
while row[1] not in status:
print(f'\n\t{red} >> Only x, /, . or \'empty\' accepted!{red.OFF}')
row[1] = input('\t >> Change Status (x, /, . or space ): ').lower()
else:
print(f'\t{green} >> ToDo Status updated!{green.OFF}', end='')
print(row)
completed.append(row)
if Found == False:
print(f'\t{red} >> ToDo Not Found cannot update Status {red.OFF}')
else:
with open('todos.csv', 'w', newline='', encoding='utf-8') as f:
update = csv.writer(f)
update.writerows(completed)
view_all_todos()

def priority_todo():
with open('todos.csv', 'r', newline='', encoding='utf-8') as f:
editrow = int(input('\t >> Which ToDo \'Priority\' do you want to edit?: '))
data = csv.reader(f)
completed = []
Found = False
for row in data:
if row[0] == str(editrow):
Found = True
priorities = ['A','a','b', 'B','c', 'C', '']
row[2] = input('\t >> Change Priority (A, B, C or space ): ').upper()
while row[2] not in priorities:
print(f'\n\t{red} >> Only a/A, b/B, c/C or \'empty\' accepted!{red.OFF}')
row[2] = input('\t >> Change Priority (A, B, C or space ): ').upper()
else:
print(f'\t{green} >> Updated Row: {green.OFF}', end='')
print(row)
completed.append(row)
if Found == False:
print(f'\t{red} >> ToDo Not Found cannot update Priority{red.OFF} ')
else:
with open('todos.csv', 'w', newline='', encoding='utf-8') as f:
update = csv.writer(f)
update.writerows(completed)
view_all_todos()

def view_all_todos():
print(f'\n\t{blue} ### ToDo\'s: Status: x - completed, / - partial, • - paused. Priority: A, B or C ###{blue.OFF}')
print('\t','-'*130)
print(f'\t{Effect.BOLD} ID: x A CreatedOn Description tags: project @context DueDate {Effect.BOLD_OFF}')
print('\t','.'*130)
with open('todos.csv', 'r', newline='', encoding='utf-8') as f:
data = DictReader(f)
for row in data:
values = list(row.values())
ID = values[0] # auto generated?
COMPLETED = values[1] # empty, x - completed, / - partial or • - started
PRIORITY = values[2] # A, B, or C
CREATED = values[3] # date: YYYY-mm-dd
DESCRIPTION = values[4] # max 60 chars
PROJECT = values[5]
CONTEXT = values[6] # @something
DUE = values[7] # date: YYYY-mm-dd
print(f'\t{ID:>3}: {COMPLETED:2} {PRIORITY:2} {CREATED:<10} {DESCRIPTION:<60} {PROJECT:<12} {CONTEXT:<12} {DUE:<10}')
print('\t','-'*130)

def quit():
exit()

# Main Menu
menu = {
1: 'Add ToDo',
2: 'Delete ToDo',
3: 'Change Status',
4: 'Change Priority',
0: 'Quit',
}

def main_menu():

print(f'\n\t{blue} Main Menu{blue.OFF}')
print('\t','-'*20)
for key in menu.keys():
print('\t',key, '--', menu[key] )

if __name__=='__main__':
f = pyfiglet.figlet_format('\t\tToDo App', font="graceful")
print(f)
view_all_todos()
while True:
main_menu()
user_input = ''
try:
user_input = (int(input('\n\t >> Choose an option from the menu: ')))
except:

print(f'\n\t{red} >> Wrong input. Please enter a number...{red.OFF}')
if user_input == 1:
add_todo()
elif user_input == 2:
delete_todo()
elif user_input == 3:
status_todo()
elif user_input == 4:
priority_todo()
elif user_input == 0:
print(f'\t{Effect.BOLD}{yellow} >> Thank you, Goodbye.{yellow.OFF}{Effect.BOLD_OFF}\n')
quit()
else:
print(f'\t{red} >> Invalid priority, try again.!{red.OFF}')

Find it here in my: Codeberg Repo

  • code
  • dev
  • python
© matthew@analoguelife | 2024-01-18 14:10