Tom-Ainsworth / tu_du_

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

TU_DU_

Live Site

Tu_Du_ To open links in a new tab: Hold 'Command' + click on Mac, and 'ctrl' on Windows

Repository

tu_du_


Table of Contents



Objective

Design and deploy an interactive To Do List that connects to a local JSON file to read and write user submitted tasks The project should run in a CLI, deployed via Heroku, using Python.

This project was created to expand my knowledge of the Python programming language, and to satisfy the requirements for my Portfolio Project 3 assessment at Code Institute


Brief

Tu_Du_

The goal of this app is to provide the user with an easy to use, interactive to do list, to help them be more productive throughout the day.

The app should:

  • Be programmatically error free
  • Be written using Python
  • Handle all user input errors gracefully and appropriately
  • Give clear instructions regarding use and valid inputs
  • Store user inputted data in a JSON file

UX − User Experience Design

User Requirements

Some example user stories which will affect the design

First Time User

"As a procrastinator, I would like to write down my daily goals to keep track of them and be more productive"

"As a tech nerd I want to see if I can create a to do list app that functions properly and validates input"

"As a developer new to Python, I would like to build my skills using a command line interface"

Returning User

"As a returning user, I would like to create multitple lists to seperate my tasks into categories"

"As a returning user, I would like to save my lists for the next time I come and use the app"

"As a returning user, I would like to start again from scratch so I can create better lists now I know how to use the app"

Initial Concept

I intend to build a to do list inspired by the app Todoist on the Apple App Store. While my app will not be anywhere near as sofisticated, I plan on using a JSON file to store the lists locally, and then use Python methods to read, write and remove data from the JSON file. To me this works in a similar fashion to connecting with a google sheets API, however having done that in the "Love Sandwiches" guided project, I thought using JSON would be an added challenge as I haven't worked with it as a separate file before.

Wireframes

Due to the nature of this project the wireframes are very basic. There is only one page and the design does not change across any devices, only a change in content.

Desktop

Desktop Wireframe


Logic

I used flowcharts and bullet lists to map out how the app would work, so that I had a better idea of what needed to be done, and how I could store and call data. At first I wrote down a list of possible functions, and how they would interact with each other. This formed the base for the project, but as I progressed, I found that extra functions, or different approached needed to be taken. I used Apple's built in Notes app to do the first list mockup on iOS, and later Lucid to create the flowcharts. It has a variety of symbols and is really intuitive for beginners like me.

Initial Plan

Initial Plan

Function Ideas

Function Ideas

Main Flow

Main Flow Chart

Create List Flow

Create Lists Flow Chart

JSON Data Structure

JSON Structure


Features

Existing Features

UX

"As a procrastinator, I would like to write down my daily goals"

  • The app allows users to create a list using the "Create New List" option, and then "Add a Tu_Du_" to add daily goals or other tasks.

"As a tech nerd, I want to create a to do list app that validates input"

  • When users enter either a list name, or a Tu_Du_ name, code checks for both empty inputs, as well as whitespaces such as " " as an input. It then prints a message and loops back around for the user to try again.

"As a developer new to Python, I would like to build my skills using a command line interface"

  • By completing this project, I have demonstrated my ability to create a functioning CLI app, which has taken a lot of work and research to build.

"As a returning user, I would like to create multitple lists to seperate my tasks into categories"

  • Users can create as many lists as they wish and name them whatever they choose. This could include "Shopping", "Cleaning" "Work" as a few examples.

"As a returning user I would like to save my lists"

  • The "Save All Lists" menu option writes all lists and tasks to the lists.json file, so on the next load, users can continue where they left off.

"As a returning user I would like to start again from scratch"

  • The "Reset All Lists menu option will erase all user created lists, and load the default "Example List". This option doesn't require the user to save as it will write the changes to lists.json as well.

Features Left to Implement

I am really pleased with the final result of this app. To further develop it, the following features would be very useful:

  • Username and/or Password validation
    • Users can currently Save or Reset lists, but should another user use the app, they could overwrite the original work.
  • Completed Tasks score
    • Currently users get a message once they have completed a Tu_Du_, but knowing how many they have completed in total would create a positive emotional response, giving an incentive to continue using the app
  • Mouse Click support
    • Currently the app relies on up/down/enter keys to choose options. PyInquirer does support mouseclicks, however with the options being so close together, I opted not to add this yet to avoid unwanted user error and frustration.
  • Nested lists
    • Should a user want to create a subfolder within a primary list, this could be quite useful.

Data Model

A local JSON file was used to hold the lists. I went through a few iterations before landing on the current design. I haven't used separate JSON files before, and it was something that I wanted to implement on my previous project Sorting Hat Quiz. I first thought of using a Google Sheet to hold the data, however as mentioned in the Initial Concept section, I was brand new to using JSON, and therefore opted to challenge myself. The current version makes use of a nested dictionary within the "Lists" list within lists.json The keys are the list names, and their values are a nested list of tasks or Tu-Du's. This made it easy to access the data, and meant that the object never gets too deep.

Technologies Used

Python Packages

  • json
    • JavaScript Object Notation, used for displaying and storing all lists and tasks. (See Data Model Section)
  • time
    • sleep: stalls the program for a defined time
  • art
    • tprint: Prints blown up strings in various fonts. I chose the default, but there are some really interesting ones!
  • PyInquirer
    • prompt: Define a list of questions and hand them to "Prompt" which gives back a list of "Choices" to be selected. Used for all of the menus.

Other Tech

  • Python
    • Used to create the content of the app itself.
  • HTML
    • Code Institute template files to create the terminal when deployed.
  • CSS
    • Code Institute template files to create the terminal when deployed.
  • JavaScript
    • Code Institute template files to create the terminal when deployed.
  • Balsamiq
    • Balsamiq was used to create wireframes for the project.
  • PEP8 online
    • An online Python code validation service.
  • Heroku
    • Used to deploy and host the app
  • Gitpod
    • IDE used for creation and version control via Github.
  • Tiny PNG
    • Used to compress all images features in this readme.

Testing

Python Testing

Manual Python Testing

The specification within the project requires manual testing. I have performed multiple tests on the deployed site and during the development stage to ensure data is handled correctly and all functions are carrying out their intended actions.

Where user inputs are required, strip() has been used to test for empty inputs, or whitespace inputs.

All other functions of the app use the Prompt feature, so users can only select from a list of set inputs.

There were only 2 warnings found, one is a known error. The other is because I used the "global" keyword within a function. While not ideal practice having global variables of any kind, the keyword was necessary in order to properly update the json file, and allow the app to continue operating with the most recent data.

The warnings can be seen here:

Pylint Warnings

PEP8 Testing

The Python files have all been run through PEP8 online. The results are displayed here. No warnings or errors were found.

Other Python Testing

Two Python linters were used during the creation of this project.

While I found for the majority of the time they both alerted me to identical issues. They both had their individual uses to keep my code looking tidy and running properly.


Bugs

Current

  • Unwanted text appears after a prompt answer if user presses enter before prompt appears to begin with. Text Bug

    I'm not completely sure how to fix this, as adding something to catch the error would throw up more unwanted text. The bug itself does not negatively affect anything major. The first Prompt activates after the opening text finished, which in this instance opens the Instructions Page (which I would rather people use initially anyway.)

    If a user pressed enter before any of the other prompts show, it will also choose the first option on the list. If this happens when an input is required, it will not enter the blank input.


Resolved

  1. App wasn't deploying to Heroku properly
  • Commit: 3177ccf To fix this I had to add the installed packages to requirements.txt. I then made sure to do this each time I added a new library/package.
  1. QUESTIONS formerly named main_menu only had local scope and so wasn't very repeatable
  • Commit: d9f96d0 As mentioned, main_menu is now named QUESTIONS to avoid confusion with the show_main_menu(). Originally this was placed within the function, however I realised it wasn't very repeatable and I was having to copy/paste the entire dict to change choices key. I opted to make this a global variable, allowing me to edit choices in various places, and keep the prompts unified throughout the app.
  1. Deciding how to read/write to lists.json
  • Commit: 705d537
  • Commit: 6409c25
  • Commit: 4965ebc
  • Commit: 226da97
  • The above commits all relate to the same issue. As I am new to using JSON files, I went through several ways of accessing the data in lists.json. At first, I was using with open() statements for reading, then writing data Commit: 705d537. This was a long winded way of doing it, as it wasn't necessary to update the list after each user change. I instead finally opted to open the file at the start of the program Commit: 6409c25. Then write to it only when necessary, in the save_all_lists() and reset_all_lists() functions. All other manipulation took place within the program, so users could still see the changes Commit: 4965ebc, Commit: 226da97.
  1. Removing unused files
  • Commit: ee982ce At various times towards the end of the project I tried to hand off functions to seperate files in an attempt to clean up run.py. This resulted in several circular imports. I resolved these imports by only having the necessary code, but as you can see from the above commit, it left only 1-2 lines. I didn't think this was worth the change, and issues caused by the change, so I kept all task/list handling in run.py.
  1. Prompt would ask user to complete tasks even when the list was empty
  • Commit: acd94e3 I added an if not statement to check for an empty list, and only show the relevant options if so.
  1. Within the Complete a Tu_Du_ option, "Return to Main Menu" was being appended as a string to the selected_list
  • Commit: f77c378 The plan here was to append a menu option so users could go back without completing a task. Thanks to testing by Maya Claveau, she found this bug, which I then fixed by adding `get_menu_options(selected_list).
  1. save_all_lists() & reset_all_lists() were not updating the global variables
  • Commit: a135c9b I had not realised that the global variables I created on lines 13-15 did not update themselves when their 'parent' variable did. To fix this, I added statements to reset_all_lists() once I had written to lists.json so show_exisiting_lists() would update the content displayed.
  1. Users could submit blank list or Tu_Du_
  • Commit: 74f495f
  • Commit: f59e6f8
  • These commits add the same check to different inputs. I used the split() method along with a while loop to catch any empty inputs, or whitespace inputs from spaces. This will display a message for the user, then ask them to try another input.

Development

The app was made using Github

GitHub

GitHub Website

  • Sign in to GitHub.
  • I used a template created by Code Institute that can be accessed here and is available for public use via the Use this template button.

Working With Python

This section assumes you are working from the template mentioned above, as this is the first python project I have worked on.

Packages

To install all packages within this repo you can run pip freeze and then copy/paste the result.

To install individual packages you need to review the appropriate documentation for the install command. All packages I have found and used were installed using something similar to pip install time. The documentation files are linked above under the python packages heading.

To run a file from the terminal I pressed the small "play button" icon in the top right corner of the screenshot to run the file. Alternatively, you can open the file you wish to run, and type python3 file_name in the terminal. play button

Deployment

Heroku

  • Navigate to your heroku dashboard
  • Click "New" and select "Create new app".
  • Input a meaningful name for your app and choose the region best suited to your location.
  • Select "Settings" from the tabs.
    • Click "Reveal Config Vars".
      ![Config vars button](
    • Input PORT and 8000 as one config var and click add.
    • Click "Add buildpack".
    • Add "python" and "nodejs" from the list or search if necessary, remember to click save.
    • Python must be the first buildpack. They can be dragged into the correct position if needed.
  • Select "Deploy" from the tabs.
    • Select "GitHub - Connect to GitHub" from deployment methods.
    • Click "Connect to GitHub" in the created section.
    • Search for the GitHub repository by name.
    • Click to connect to the relevant repo.
    • Either click Enable Automatic Deploys for automatic deploys or Deploy Branch to deploy manually. Manually deployed branches will need re-deploying each time the repo is updated. Automatic will build the app each time you use you add, commit and push new code.
    • Click View to view the deployed site.

The site is now live and operational


Credits

Content

  • The terminal function and template for the deployable application was provided by Code Institute, with special mention to Matt Rudge

Acknowledgements

  • Thank you to Ed Barron. He's an incredible engineer who helped with a lot of syntax based issues I was having, particularly with reading/writing to lists.json I feel very lucky to know him and be able to pick his brain. He's helped me no end with understanding the why and how of what I'm writing.

  • Thank you to Spencer Barriball He's been an amazing mentor and has put my mind at ease with several course based issues. Before starting this project we brainstormed ideas for what would be achievable, and it really gave me the confidence I needed to just get started with this.

  • As always hank you to Dave Horrocks for providing an incredibly detailed readme template to use, and just in general for being super helpful anytime I've had an issue or question.

  • A special thanks to Maya Claveau for continuously breaking the app during testing, allowing me to squish several bugs I otherwise would not have known existed!

About


Languages

Language:Python 43.2%Language:HTML 28.1%Language:Dockerfile 15.3%Language:JavaScript 13.4%