Flash-CLI: Command-Line Vocabulary Training
Flash-CLI is a Python-based command-line flashcard application that seamlessly integrates with Google Sheets. Enhance your skills, compare your progress with everyone who used the app before, and master all kinds of flashcards — all from a Command Line Interface.
Some useful links:
-
Link to the google Spreadsheet: This is the Google Spreadsheet that the app uses to store the flashcards.
Flash-CLI is designed for anyone who wants to expand their vocabulary and improve their language skills. The app is suitable for students, language learners, and professionals who want to learn new words and concepts efficiently.
The app is designed to be user-friendly and accessible to everyone, regardless of their technical background. It's a lightweight and fast tool that allows users to focus on learning without distractions.
Flash-CLI sets itself apart because it provides real-time feedback based on the user's performance and the community's performance. This feature motivates users and helps them put their progress into perspective.
| As a | I want to | so that I can |
|---|---|---|
| User | review flashcards in the terminal | focus on learning without distractions |
| User | choose between multiple quiz modes | practice different quiz modes according to my preference and skill level |
| User | review a random flashcard and indicate if I knew the definition or not | test my memory of the definition, get immediate feedback, and update the flashcard status |
| User | see a word and type the definition in typed answer mode | test my recall and understanding of the definition, get immediate feedback, and update the flashcard status |
| App provider | sync the flashcards with Google Sheets | easily create and edit flashcard decks online |
| User | receive real-time feedback based on my performance and the community's performance | monitor my progress and compare with others |
| User | avoid frustration and confusion when an error happens or when I enter invalid input | have a smooth and enjoyable user experience |
| User | use keyboard shortcuts and efficient navigation in the terminal | improve my productivity and user experience |
The terminal is an ideal environment for vocabulary training for several reasons:
- Focus on Learning: By removing distractions (fancy UI elements, animations, etc.), the terminal allows users to concentrate solely on expanding their vocabulary.
- Efficiency: Terminal apps are lightweight and fast. Users can quickly launch the app, practice, and exit, thereby maximizing their time spent learning.
- Keyboard-Centric Interaction: Terminal apps encourage keyboard shortcuts and efficient navigation, which aligns well with learning and memorization.
Note: For this specific project, the terminal environment is emulated within a browser for ease of initial access. However, the app is designed to be used in a traditional terminal environment.
The app provides a main menu with options to choose between different quiz modes and to exit the app. Users can navigate the app using keyboard shortcuts that are displayed in the menu. If the user wishes to have more information about the options, they can use the help (?) command. All invalid inputs are handled gracefully, and the app provides helpful messages to guide users.
Functionality:
- Display a random flashcard only with the word (question).
- Upon user input, reveal the definition (answer).
- Prompt the user to indicate if they knew the answer or not.
- Update the flashcard status based on the user's response.
- Provide personalized feedback based on the user's responses and the responses of the community so far.
This mode is designed to help users with initial learning and self-assessment. It's a simple and effective way to memorize new flashcards.
Functionality:
- Display a word (question).
- Prompt the user to type the definition (answer).
- Check the user's input against the correct definition.
- If the user's input is incorrect, display the correct definition and ask the user if they want to count their attempt as a success or failure.
- Update the flashcard status based on the user's responses.
- Provide personalized feedback based on the user's responses and the responses of the community so far.
This mode is designed to test the user's recall and understanding of the flashcard. It's a more challenging and interactive way to practice and reinforce learning.
Screenshot of Typed Answer Mode:

The app automatically syncs flashcard data with a connected Google Sheets document using the Google Sheets API. No user login is required.
The Google Sheet is set up so that every worksheet is a deck of flashcards. Each row represents a flashcard, with the word in the first column and the definition in the second column. Further columns are used to store the status of the flashcard.
Keep in mind that the Google sheet is not accessible by the user and only used as a database for the app. Instead, the sheet is very helpful for the app provider to manage and update flashcards online.
Screenshot of the Google Sheets Sync feature:

Link to the Google Sheets document used by the app.
Screenshot of the Google Sheets document used by the app:

Note: In the Google Sheets document there are two special worksheets:
- short quiz for testing - This worksheet is used for testing the quiz functionality. It contains only 3 flashcards. That way, the quiz can be tested quickly.
- *python (review mode not supported yet) - This worksheet is an interesting python quiz that only works with the quiz modes, because its content is too long for it to be displayed in review mode.
The app will provide personalized and dynamically generated feedback based on collective performance. Feedback is given after answering most questions and at the end of each quiz. It's designed to motivate users and help put their progress into perspective.
Here are some examples of the feedback:
- "Great job! You're part of the 70% of people who knew the answer!"
- "You're doing better than 30% of people who attempted this flashcard."
- "Congratulations, you got 80% of the questions right!"
- "You knew the answer! Great job!"
- "Don't worry, less than half of the people who attempted this flashcard knew the answer."
- "You're doing better than 40% of people who attempted this flashcard."
- "You wrote the correct answer! Great job!"
Screenshot of Real-Time Feedback:

Flash-CLI gracefully handles unexpected errors and provides helpful messages to guide users. Additionally, the app logs application events for debugging and troubleshooting.
If an error with the Google Sheets API occurs, the app will prompt the user to decide whether to try to reconnect or quit the program. This is achieved using a custom built helper function.
This is achieved using a custom built helper function:
def handle_exception(e: Exception, message: str) -> Union[None, NoReturn]:
"""
Handles an exception by printing an error message and logging the error.
The user is prompted to decide whether to reconnect or quit the program.
Args:
e (Exception): The exception that occurred.
message (str): The error message to display.
Returns:
None: If the user decides to reconnect.
NoReturn: If the user decides to quit the program. (Exits the program)
"""
print(message)
print(f"Error details: {e}")
logging.exception(f"{message} Error details: %s", str(e))
quitting = input("Do you want to try connecting again? (y/n)\n").lower()
if quitting == "y":
print("Reconnecting ...")
return
else:
confirmation = input(
"Are you sure? If you enter 'y', the program will quit. (y/n)\n"
).lower()
if confirmation == "y":
print("Quitting due to error.")
sys.exit(1)
else:
print("Reconnecting ...")
returnAn example of how this function is called (simplified):
def connect_to_spreadsheet() -> gspread.models.Spreadsheet:
"""
Connects to the Google Sheets document and returns the spreadsheet object.
Returns:
gspread.models.Spreadsheet: The spreadsheet object.
"""
while True:
try:
# more code ...
SHEET = GSPREAD_CLIENT.open(SPREADSHEET_NAME)
except gspread.exceptions.SpreadsheetNotFound as e:
handle_exception(e, "Failed to find spreadsheet: '{SPREADSHEET_NAME}'")
else:
print(f"Connected to spreadsheet: '{SPREADSHEET_NAME}'")
return SHEETInvalid input: If the user enters an invalid command or input, the app will display a helpful message and prompt the user to try again.
Example:
Screenshot of Invalid Input Handling:

-
Quiz Modes
- Multiple-Choice Quizzes: Randomized questions with answer choices.
- Timed Quizzes: Set a time limit for answering questions.
-
Flashcard Management
- Create, edit, and delete flashcard decks.
-
Statistics and Analytics
- Display global progress (e.g., percentage of how many people knew an answer).
- Show performance trends over time (graphs, charts).
-
Use language APIs (e.g., WordNet, Google Translate) for:
- Synonyms and antonyms
- Example sentences
- Word definitions
- Pronunciations
-
Gamification
- Points and Badges: Reward users with points for completing quizzes or achieving milestones.
-
Customizable Themes
- Allow users to choose color schemes for the terminal interface (e.g., light mode, dark mode).
- Use the rich library to create a more visually appealing interface.
-
Backup and Restore
- Regularly back up data (flashcards, progress) to prevent data loss.
- Google Sheets API as the database for flashcards.
- Quizlet for inspiration and comparison.
- HTML used to display a terminal in the browser.
- Python used as the back-end programming language (main focus of the project).
- Git used for version control. (
git add,git commit,git push) - for this project i additionally learned how to usegit add -p,git diff,git log,git resetand some more commands to get a better understanding of the git workflow. - GitHub used for secure online code storage.
- Gitpod used as a cloud-based IDE for development.
- Heroku used for hosting the deployed back-end site.
- Markdown Builder by Tim Nelson used as a template for the README.md file.
- draw.io used for Flowchart creation
- Windows Snipping Tool used to take screenshots and screencasts on Windows
- Github Issues used for issue tracking
- GitHub Projects used for project management in conjunction with GitHub Issues
- shields.io used to create the badges in the README.md file
- LICEcap used to create GIFs for the TESTING.md file
- markdown-link-check used to check for broken links in the README.md file
- copy-credits.py used to automatically generate the credits for the README.md file (this script was written by me as a side project, using much help from the Microsoft Edge Copilot)
Screenshot of the Github Projects Board:

To follow best practice, a flowchart was created for the app's logic, and mapped out before coding began using a free version of Draw.io.
Below is the flowchart of the main process of this Python program. It shows the entire cycle of the program.
The program uses two classes as a blueprint for the project's objects (OOP).
The Flashcard class represents a single flashcard, and the Flashcard_Set class represents a set (deck) of flashcards.
A number of Flashcard objects are stored in a Flashcard_Set object.
The objects are created using the data from the Google Sheets document. In the document, a worksheet represents a Flahscard_Set and each row represents a Flashcard.
class Flashcard:
"""
A class to represent a flashcard.
Attributes:
question (str): The question on the flashcard.
answer (str): The answer to the question on the flashcard.
progress_dict (dict): A dictionary to track the
progress of the flashcard.
Methods:
show_question(): Prints the question on the flashcard.
show_answer(): Prints the answer to the question on the flashcard.
update_progress(progress_key: str): Updates the
progress of the flashcard.
"""
def __init__(self, question: str, answer: str, progress_dict: dict):
self.question = question
self.answer = answer
self.progress_dict = progress_dict
def show_question(self) -> None:
# function code
def show_answer(self) -> None:
# function code
def update_progress(self, progress_key: str) -> None:
# function codeclass Flashcard_Set:
"""
A class to represent a set of flashcards.
Attributes:
title (str): The title of the flashcard set.
flashcards (List[Flashcard]): The flashcards in the set.
Methods:
_load_flashcards(): Loads the flashcards from the worksheet data.
show_all(): Displays all the flashcards in a table format.
upload(): Prepares the flashcard data and uploads it to the
Google Sheets worksheet.
Note: The methods above all use helper methods to perform their tasks.
These helper methods are not listed here.
"""
def __init__(self, title: str):
"""
Initializes a Flashcard_Set object.
Uses the _load_flashcards method to load the flashcards from the
worksheet data.
"""
self.title = title
self.flashcards = self._load_flashcards()
def _load_worksheet_data(self) -> List[Dict[str, Union[int, float, str]]]:
# ...
def _create_flashcard_from_row(
self,
row: Dict[str, Union[int, float, str]]
) -> Flashcard:
# ...
def _load_flashcards(self) -> List[Flashcard]:
# ...
def show_all(self) -> None:
# ...
def _convert_to_list_of_lists(self) -> list[list]:
# ...
def _prepare_data_for_upload(self) -> list:
# ...
def _upload_data_to_worksheet(self, data: list) -> None:
# ...
def upload(self) -> None:
# ...The primary functions outside of the classes used on this application are:
pick_set(): Allows the user to choose a set of flashcards to practice.give_feedback_card()andgive_feedback_set(): Provides personalized feedback based on the user's performance and the community's performance.pick_mode(): Allows the user to choose between different quiz modes and other actions. This function is the main menu of the app.flashcard_mode(): The flashcard mode allows the user to review flashcards and decide if they know the answer.typed_answer_mode(): The typed answer mode allows the user to type their answers directly.
I've used the following Python packages and external imported packages.
import sys: sys is used for system-specific parameters and functions. In this project, it's used to exit the program.import os: os provides a way of using operating system dependent functionality. In this project, it's used to clear the terminal.import random: random is used for generating random numbers.import time: time provides various time-related functions. In this project, it's used to the sleep function.from typing import Dict, List, NoReturn, Tuple, Union: These are used for type hinting in function signatures and variable declarations.import gspread: gspread is used for interacting with Google Spreadsheets.from google.oauth2.service_account import Credentials: Credentials is used for authenticating with the Google Sheets API.import logging: logging is used for logging errors, information, and warnings.from prettytable import PrettyTable: PrettyTable is used for creating ASCII art tables. In this project, it's used to display a flashcard deck in a table format.
For all testing, please refer to the TESTING.md file.
Code Institute has provided a template to display the terminal view of this backend application in a modern web browser. This is to improve the accessibility of the project to others.
The live deployed application can be found deployed on Heroku.
This project uses Heroku, a platform as a service (PaaS) that enables developers to build, run, and operate applications entirely in the cloud.
Deployment steps are as follows, after account setup:
- Select New in the top-right corner of your Heroku Dashboard, and select Create new app from the dropdown menu.
- Your app name must be unique, and then choose a region closest to you (EU or USA), and finally, select Create App.
- From the new app Settings, click Reveal Config Vars, and set the value of KEY to
PORT, and the value to8000then select add. - If using any confidential credentials, such as CREDS.JSON, then these should be pasted in the Config Variables as well.
- Further down, to support dependencies, select Add Buildpack.
- The order of the buildpacks is important, select
Pythonfirst, thenNode.jssecond. (if they are not in this order, you can drag them to rearrange them)
Heroku needs two additional files in order to deploy properly.
- requirements.txt
- Procfile
You can install this project's requirements (where applicable) using:
pip3 install -r requirements.txt
If you have your own packages that have been installed, then the requirements file needs updated using:
pip3 freeze --local > requirements.txt
The Procfile can be created with the following command:
echo web: node index.js > Procfile
For Heroku deployment, follow these steps to connect your own GitHub repository to the newly created app:
Either:
- Select Automatic Deployment from the Heroku app.
Or:
- In the Terminal/CLI, connect to Heroku using this command:
heroku login -i - Set the remote for Heroku:
heroku git:remote -a app_name(replace app_name with your app name) - After performing the standard Git
add,commit, andpushto GitHub, you can now type:git push heroku main
The frontend terminal should now be connected and deployed to Heroku!
This project can be cloned or forked in order to make a local copy on your own system.
For either method, you will need to install any applicable packages found within the requirements.txt file.
pip3 install -r requirements.txt.
If using any confidential credentials, such as CREDS.json or env.py data, these will need to be manually added to your own newly created project as well.
You can clone the repository by following these steps:
- Go to the GitHub repository
- Locate the Code button above the list of files and click it
- Select if you prefer to clone using HTTPS, SSH, or GitHub CLI and click the copy button to copy the URL to your clipboard
- Open Git Bash or Terminal
- Change the current working directory to the one where you want the cloned directory
- In your IDE Terminal, type the following command to clone my repository:
git clone https://github.com/benschaf/flash-cli.git
- Press Enter to create your local clone.
Alternatively, if using Gitpod, you can click below to create your own workspace using this repository.
Please note that in order to directly open the project in Gitpod, you need to have the browser extension installed. A tutorial on how to do that can be found here.
By forking the GitHub Repository, we make a copy of the original repository on our GitHub account to view and/or make changes without affecting the original owner's repository. You can fork this repository by using the following steps:
- Log in to GitHub and locate the GitHub Repository
- At the top of the Repository (not top of page) just above the "Settings" Button on the menu, locate the "Fork" Button.
- Once clicked, you should now have a copy of the original repository in your own GitHub account!
Since this project is a backend application, the local version is not significantly different from the live deployment on Heroku. The main difference is that the local version is run in a terminal environment, while the live deployment is emulated in a modern web browser.
The emulated CLI has some quirks and limitations compared to a traditional terminal environment. Some libraries tend to behave differently in the emulated environment, and the terminal view is limited to 80 columns by 24 rows. This means that each line of text needs to be 80 characters or less, otherwise it will be wrapped onto a second line. Additionally, the clear terminal function does not work as expected in the emulated environment.
All of these differences are taken into account during development, and the app is designed to work seamlessly in both environments.
All the Credits and hyperlinks can be found in the run.py file on the indicated lines.
Note that this list of credits is automatically generated from the run.py file using the copy-credits.py script. The script was written by me, with much help from the Microsoft Edge Copilot.
-
Line: 11: Credit for prettytable
-
Line: 14: Credit for error logging
-
Line: 16: Credit for formatting of log messages
-
Line: 23: Credit for clear Terminal function
-
Line: 38: Credit for exception handling
-
Line: 41: Credit for NoReturn type hint
-
Line: 44: Credit for parameter type hints
-
Line: 80: Credit for using the google sheets API
-
Line: 138: Credit for writing docstrings
-
Line: 692: Credit for join method
-
Line: 702: Credit for case insensitive inputs
-
Line: 757: Credit for sleep function
-
Line: 894: Credit to Tim Nelson (CI Mentor) for calling the main function like that.
-
Line: 916: Credit for line break
- French Flashcard Set: CJHSalmeron on Quizlet
- German Flashcard Set: Rubir22 on Quizlet
- Python Flashcard Set: Tash207 on Quizlet
- I would like to thank my Code Institute mentor, Tim Nelson for his support throughout the development of this project.
- I would like to thank the Code Institute tutor team for their assistance with troubleshooting and debugging some project issues.
- I would like to thank the Code Institute Slack community for the moral support and for providing a great environment for learning and sharing knowledge.
- I would like to thank my wife Maria, for believing in me, and allowing me to make this transition into software development.




