This site is from a past semester! The current version will be here when the new semester starts.

The Monty Project

The Monty Python Comedy Group,
[credit: Wikipedia]

The Monty Project is an educational software project designed to take you through the steps of building a small software incrementally, while applying as many Python and SE techniques as possible along the way.

The project aims to build a product named Monty, a Personal Assistant Chatbot that helps a person to keep track of various things. The name Monty was chosen as a placeholder name, in honor of the Monty Python comedy group whose work inspired the name of the the Python language. You may give it any other name and personality you wish.

Here is a sample interaction with Monty:

*******************************************************************************************
*  __          __  _                            _          __  __             _           *
*  \ \        / / | |                          | |        |  \/  |           | |          *
*   \ \  /\  / /__| | ___ ___  _ __ ___   ___  | |_ ___   | \  / | ___  _ __ | |_ _   _   *
*    \ \/  \/ / _ \ |/ __/ _ \| '_ ' _ \ / _ \ | __/ _ \  | |\/| |/ _ \| '_ \| __| | | |  *
*     \  /\  /  __/ | (_| (_) | | | | | |  __/ | || (_) | | |  | | (_) | | | | |_| |_| |  *
*      \/  \/ \___|_|\___\___/|_| |_| |_|\___|  \__\___/  |_|  |_|\___/|_| |_|\__|\__, |  *
*                                                                                  __/ |  *
*                                                                                 |___/   *
*******************************************************************************************

>>> What can I do for you?

help
>>> I'm glad you asked. Here it is:
==================================================
Monty can understand the following commands:

  add DESCRIPTION
    Adds a task with the DESCRIPTION to the list
    Example: add read book
  done INDEX
    Marks the task at INDEX as 'done'
    Example: done 1
  exit
    Exits the application
  help
    Shows the help information
  list
    Lists the tasks in the list
--------------------------------------------------

>>> What can I do for you?

add read book
>>> Task added to the list
>>> What can I do for you?

add return book
>>> Task added to the list
>>> What can I do for you?

done 1
>>> Congrats on completing a task! :-)
>>> What can I do for you?

list
>>> Here is the list of tasks:
==================================================
STATUS | INDEX | DESCRIPTION
--------------------------------------------------
  X    |   1   | read book
  -    |   2   | return book
--------------------------------------------------
>>> What can I do for you?

The project consists of the following increments:

  • Levels: A series of features, meant to be added to Monty in the given order, although some can be skipped. These have been named Level 1 to Level 14 to indicate how each makes the product progressively "level up".
  • Extensions:
    • Category B These are enhancements related to task tracking.
    • Category C These are enhancements, not specifically related to task tracking.
    • Category D Each of these adds the ability to track another type of entities.

Levels

Level 1 Echo Once

Write a Python program to read in one user command and repeat it back to the user. An example output is given below.

>>> Hello, my name is Monty
>>> What can I do for you?
foo
>>> Your command is: foo
>>> Bye!

Level 2 Recognize Known Commands

Extend Monty 1 code to work as follows:

  • It recognizes the list command and responds with a fixed message.
  • It recognizes the exit command and exits the program if user confirms.
  • For all other inputs, it responds with a fixed error message.

A sample session is given below.

You are highly encouraged to give the software a different name (i.e., not Monty), define your own command formats (e.g., show instead of list), and even a different personality (e.g., you can make its questions/responses sound similar to a popular video game character). Differentiating your software in those ways will reduce the risk of plagiarism concerns.

>>> Hello, my name is Monty
>>> What can I do for you?

list
>>> Nothing to list
>>> What can I do for you?

foo
>>> OOPS! Unknown command
>>> What can I do for you?

exit
>>> Are you sure? y/n
n
>>> What can I do for you?

exit
>>> Are you sure? y/n
y
>>> Bye!

Level 3 Use Functions

Restructure the Monty Level 2 code to fit the following structure, while keeping the behavior same as before.

import sys


# ADD MISSING FUNCTIONS


def main():
    print_greeting()
    while True:
        command = read_command()
        execute_command(command)


main()

Level 4 Collect Tasks in Memory

Enhance the Monty Level 3 code to improve the functionality as per the sample output given below.

>>> Hello, my name is Monty
>>> What can I do for you?

list
>>> Nothing to list
>>> What can I do for you?

add read book
>>> What can I do for you?

list
>>> List of items:
     1. read book
>>> What can I do for you?

add return book
>>> What can I do for you?

list
>>> List of items:
     1. read book
     2. return book
>>> What can I do for you?

exit
>>> Are you sure? y/n
y
>>> Bye!

You can use the list slicing syntax to extract a portion of a string.


s = 'abcdefgh'
print(s[2:])
print(s[:5])
 → 

cdefgh
abcde

The above technique can be used to extract the item description from an add command.


Level 5 Mark Tasks as Done

Enhance the Monty Level 4 code in the following ways:

  • Add a done command so that the user can mark a task as done. e.g., done 2 marks the task at index 2 as done.
  • Show appropriate error messages if the user gives an invalid index for the done command
  • Optionally, implement an undone (or unmark) command to change the status of a task back to not done.

A sample output is given below.

>>> Hello, my name is Monty
>>> What can I do for you?

add borrow book
>>> What can I do for you?

add read book
>>> What can I do for you?

add return book
>>> What can I do for you?

list
>>> List of items:
     [ ] 1. borrow book
     [ ] 2. read book
     [ ] 3. return book
>>> What can I do for you?

done 1
>>> What can I do for you?

list
>>> List of items:
     [X] 1. borrow book
     [ ] 2. read book
     [ ] 3. return book
>>> What can I do for you?

done abc
>>> SORRY, I could not perform that command. Problem: abc is not a number
>>> What can I do for you?

done 5
>>> SORRY, I could not perform that command. Problem: No item at index 5
>>> What can I do for you?

done 0
>>> SORRY, I could not perform that command. Problem: Index must be greater than 0
>>> What can I do for you?

garbage
>>> SORRY, I could not perform that command. Problem: Command not recognized
>>> What can I do for you?

exit
>>> Are you sure? y/n
y
>>> Bye!

Each task has two data values: the description and the 'done' status. You can use a list to hold these two data items. That means your list of tasks will be a list containing lists. Example:

tasks = []
tasks.append(['read book', False])
print('Description of the first task:', tasks[0][0])

if tasks[0][1]:
    print('X')
else:
    print('-')

You can use exceptions to identify and handle errors in the command.

def main():
    print_greeting()
    while True:
        try:
            command = read_command()
            execute_command(command)
        except Exception as e:
            print('>>> SORRY, I could not perform that command. Problem:', e)

Level 6 Give Help

Enhance the Monty Level 5 code in the following ways:

  • Add a help command so that the user can view how to use the app.
  • Improve the formatting of the text displayed to the user to make the user experience nicer.

A sample output is given below.

*******************************************************************************************
*  __          __  _                            _          __  __             _           *
*  \ \        / / | |                          | |        |  \/  |           | |          *
*   \ \  /\  / /__| | ___ ___  _ __ ___   ___  | |_ ___   | \  / | ___  _ __ | |_ _   _   *
*    \ \/  \/ / _ \ |/ __/ _ \| '_ ' _ \ / _ \ | __/ _ \  | |\/| |/ _ \| '_ \| __| | | |  *
*     \  /\  /  __/ | (_| (_) | | | | | |  __/ | || (_) | | |  | | (_) | | | | |_| |_| |  *
*      \/  \/ \___|_|\___\___/|_| |_| |_|\___|  \__\___/  |_|  |_|\___/|_| |_|\__|\__, |  *
*                                                                                  __/ |  *
*                                                                                 |___/   *
*******************************************************************************************

>>> What can I do for you?

help
>>> I'm glad you asked. Here it is:
==================================================
Monty can understand the following commands:

  add DESCRIPTION
    Adds a task to the list
    Example: add read book
  done INDEX
    Marks the task at INDEX as 'done'
    Example: done 1
  exit
    Exits the application
  help
    Shows the help information
  list
    Lists the tasks in the list
--------------------------------------------------

>>> What can I do for you?

add read book
>>> Task added to the list
>>> What can I do for you?

add return book
>>> Task added to the list
>>> What can I do for you?

done 1
>>> Congrats on completing a task! :-)
>>> What can I do for you?

list
>>> Here is the list of tasks:
==================================================
STATUS | INDEX | DESCRIPTION
--------------------------------------------------
  X    |   1   | read book
  -    |   2   | return book
--------------------------------------------------
>>> What can I do for you?

You can use triple quotes to define a long string such as the help text.

help_text ='''
long text
more text
'''

You can generate ASCII art using online resources such as http://patorjk.com/software/taag


Level 7 Save Tasks to Disk

Enhance the Monty Level 6 code in the following ways:

  • Monty saves tasks into a csv file, and loads data from the same file at the start.
  • Add a delete command that can delete a task at a specific index.

A sample output is given below. Note the following:

  • Monty is able to show at the very start the three tasks loaded from the file.
  • When item 2 is deleted, the item previously at index 3 moves to position 2.
*******************************************************************************************
*  __          __  _                            _          __  __             _           *
*  \ \        / / | |                          | |        |  \/  |           | |          *
*   \ \  /\  / /__| | ___ ___  _ __ ___   ___  | |_ ___   | \  / | ___  _ __ | |_ _   _   *
*    \ \/  \/ / _ \ |/ __/ _ \| '_ ' _ \ / _ \ | __/ _ \  | |\/| |/ _ \| '_ \| __| | | |  *
*     \  /\  /  __/ | (_| (_) | | | | | |  __/ | || (_) | | |  | | (_) | | | | |_| |_| |  *
*      \/  \/ \___|_|\___\___/|_| |_| |_|\___|  \__\___/  |_|  |_|\___/|_| |_|\__|\__, |  *
*                                                                                  __/ |  *
*                                                                                 |___/   *
*******************************************************************************************

>>> What can I do for you?

list
>>> Here is the list of tasks:
==================================================
STATUS | INDEX | DESCRIPTION
--------------------------------------------------
  X    |   1   | borrow book
  -    |   2   | read book
  -    |   3   | return book
--------------------------------------------------
>>> What can I do for you?

delete 2
>>> Task deleted from the list
>>> What can I do for you?

list
>>> Here is the list of tasks:
==================================================
STATUS | INDEX | DESCRIPTION
--------------------------------------------------
  X    |   1   | borrow book
  -    |   2   | return book
--------------------------------------------------

here are some tips:

  • The filename can be specified in the code. e.g.,

    DATA_FILE = 'monty7.csv'
    
  • The following statement will create an empty data.csv file if the file doesn't exist, but will keep the file as it is if it already exists (it simply opens the file in append mode -- which creates the file it if it doesn't exist -- and close it right after).

    open('data.csv', 'a').close()
    
  • The format of the file is up to you. Here is an example:

    borrow book,done
    read book,pending
    return book,pending
    
  • The program can load the tasks from the file at the beginning. It can save the data after each command. For example, as follows:

     items = []
     DATA_FILE = 'monty7.csv'
    
    
     def main():
         create_file_if_missing(DATA_FILE)
         load_data(DATA_FILE) # load task data from the file
         print_greeting()
         while True:
             try:
                 command = read_command()
                 execute_command(command)
                 save_data(DATA_FILE, items) # save all tasks in the file
             except Exception as e:
                 print('>>> SORRY, I could not perform that command. Problem:', e)
    
    
     main()
    

Given below are some more features you can consider adding at this point (it is optional to add them to Monty 7):

  • Remove the need for the user to confirm before exiting Monty. As data are saved to a file, such a confirmation is no longer necessary because an accidental exit will not cause any permanent damage.
    >>> What can I do for you?
    
    exit
    >>> Bye!
    
  • Add a pending command (other possible names: undone or unmark) that can mark a task as not-done-yet (i.e., the opposite of the done command), if you haven't done that already.
     >>> What can I do for you?
    
     list
     >>> Here is the list of tasks:
     ==================================================
     STATUS | INDEX | DESCRIPTION
     --------------------------------------------------
       X    |   1   | borrow book
       -    |   2   | read book
       -    |   3   | return book
     --------------------------------------------------
     >>> What can I do for you?
    
     pending 1
     >>> OK, I have marked that item as pending
     >>> What can I do for you?
    
     list
     >>> Here is the list of tasks:
     ==================================================
     STATUS | INDEX | DESCRIPTION
     --------------------------------------------------
       -    |   1   | borrow book
       -    |   2   | read book
       -    |   3   | return book
     --------------------------------------------------
     >>> What can I do for you?
    
  • Make commands case insensitive and immune to extra leading/trailing spaces. For example, all these commands should work the same way.
    add read book
    ADD read book
    Add read book
    add    read book
        add read book
    

Level 8 Support Deadlines

Enhance the Monty Level 7 code to add support for keeping track of deadlines as well as regular todo tasks

Previous behavior:

  • add buy book: adds a task buy book

Proposed change - replace the above command with the following two:

  • todo read book: adds a todo task read book
  • deadline return book by: May 3rd adds a deadline return book which is to be done by May 3d.
    Note: by: is a keyword. Anything that comes after it is considered a description of the deadline.

A sample output is given below.

>>> What can I do for you?

list
>>> Here is the list of tasks:
============================================================
STATUS | INDEX | DESCRIPTION                 | DEADLINE
------------------------------------------------------------
  X    |   1   | borrow book                 | -
  -    |   2   | read book                   | -
  -    |   3   | return book                 | Monday
------------------------------------------------------------
>>> What can I do for you?

todo watch movie
>>> What can I do for you?

deadline submit assignment by: end of May
>>> What can I do for you?

list
>>> Here is the list of tasks:
============================================================
STATUS | INDEX | DESCRIPTION                 | DEADLINE
------------------------------------------------------------
  X    |   1   | borrow book                 | -
  -    |   2   | read book                   | -
  -    |   3   | return book                 | Monday
  -    |   4   | watch movie                 | -
  -    |   5   | submit assignment           | end of May
------------------------------------------------------------
>>> What can I do for you?

here are some tips:

  • One option is to use a list of dictionary objects to store the tasks/deadlines. Given below is an example of such a data structure. In that data structure, T and D is used to indicate todo items and deadline items, respectively.
    [
     {'type': 'T', 'description': 'borrow book', 'is_done': True},
     {'type': 'T', 'description': 'read book', 'is_done': False},
     {'type': 'D', 'description': 'return book', 'is_done': False, 'by': 'Monday'}
    ]
    
    
  • The format of the csv file needs to be updated to store extra values too. Here is an example:
    T,borrow book,done
    T,read book,pending
    D,return book,pending,Monday
    


Level 9 Use Classes

Enhance the Monty Level 8 code to use classes ToDo and Deadline (i.e., you need to define these two classes) to represent todo tasks and deadlines, respectively.
This means you no longer needs to use dict objects to represent todo/deadline tasks. That is, your tasks can be kept as a list of ToDo and Deadline objects, instead of a list of dictobjects.

A shorthand for if-else

Consider the following code:
def get_as_word(status):
    if status == 1:
        return 'Yes'
    else:
        return 'No'

The same can be written using the following shorthand for if-else:

def get_as_word(status):
    return 'Yes' if status == 1 else 'No'

A few more examples:

status_as_word = 'Yes' if status == 1 else 'No'
print('Yes') if status == 1 else print('No')
print('Yes' if status == 1 else 'No')

Note that this shorthand requires both the if part and the else part.


Level 10 Use More Classes

Enhance the Monty Level 9 code to extract the following classes:

  • UserInterface: an object of this class can be used to handle reading input from the user and showing output back to the user.
  • StorageManager: an object of this class can be used to read data from the data file and write data back to the data file.
  • TaskManager: an object of this class will hold the list of Task/Deadline objects and will execute commands.

Optional feature to consider: add a progress command that shows how many tasks/deadlines were marked as done during a session so far. Here is an example output:

>>> What can I do for you?

list
>>> Here is the list of tasks:
    ============================================================
    STATUS | INDEX | DESCRIPTION                 | DEADLINE
    ------------------------------------------------------------
      X    |   1   | borrow book                 | -
      -    |   2   | read book                   | -
      -    |   3   | return book                 | Monday
    ------------------------------------------------------------
>>> What can I do for you?

progress
>>> Progress for this session: todos 0 deadlines 0
>>> What can I do for you?

done 2
>>> Congrats on completing a task! :-)
>>> What can I do for you?

progress
>>> Progress for this session: todos 1 deadlines 0
>>> What can I do for you?

done 3
>>> Congrats on completing a task! :-)
>>> What can I do for you?

progress
>>> Progress for this session: todos 1 deadlines 1
>>> What can I do for you?

pending 2
>>> OK, I have marked that item as pending
>>> What can I do for you?

progress
>>> Progress for this session: todos 0 deadlines 1
>>> What can I do for you?

list
>>> Here is the list of tasks:
    ============================================================
    STATUS | INDEX | DESCRIPTION                 | DEADLINE
    ------------------------------------------------------------
      X    |   1   | borrow book                 | -
      -    |   2   | read book                   | -
      X    |   3   | return book                 | Monday
    ------------------------------------------------------------
>>> What can I do for you?


Level 11 Use Multiple Code Files

Enhance the Monty Level 10 code to divide the source code into multiple files (e.g., todo.py, deadline.py, etc.).


Level 12 Use Inheritance

Enhance the Monty Level 11 code to make the Deadline class inherit from the ToDo class:


Level 13 Add Unit Tests

Add some unit tests to Monty Level 12 code.

Minimum requirement: 2 unit tests, testing two functions/methods


Level 14 Add a GUI

Enhance the Monty Level 13 code to integrate it with the skeletal GUI given below.

Notes about the given version of the GUI:

  • The GUI shows the list of tasks all the time.
  • It initializes with some dummy data.
  • It only supports an add command and a help command.

Here are some screenshots of the GUI:

Skeletal GUI code


Extensions: Category B

B-Events

Events

Provide a way for the user to track events (i.e., things with a start time and an end time such as a meeting), in addition to todo and deadline tasks.


B-DoAfterTasks

'Do after' tasks

Support the managing of tasks that need to be done after a specific time/task e.g., return book after the exam is over.


B-DoWithinPeriodTasks

'Do within a period' task

Provide support for managing tasks that need to be done within a certain period e.g., collect certificate between Jan 15 and 25th.


B-FixedDurationTasks

Unscheduled tasks with a fixed duration

Provide support for managing tasks that takes a fixed amount of time but does not have a fixed start/end time e.g., reading the sales report (needs 2 hours).


Extensions: Category C

C-DetectDuplicates

Deal duplicate items

Add the ability to recognize and deal with duplicate items. e.g., the same task added multiple times.


C-FlexibleDataSource

Flexible data source

Provide more flexibility with the data source e.g., the ability for the user to specify which file to use as the data source.


C-DateTimes

Meaningful date/times

Make Monty understand the meaning of dates/times attached to a task. e.g., sort deadlines based on their dates/times


C-Sort

Sorting items managed by the App

The ability to sort items e.g., sort deadlines chronologically.

C-Update

Easily edit items

Support a way to easily edit details of items e.g., change the deadline date without changing anything else.

Minimal: the ability to update an existing item without having to delete it first

Other ideas:

  • the ability to clone items (to easily create new items based on existing items)

C-Tagging

Tagging items

Provide a way to tag items e.g., tag a task as #fun.

C-Priority

Prioritizing items

Provide a way to attach priorities to items e.g., mark an item as a high priority (or priority level 1).

C-Archive

Archiving items

Provide a way to archive items so that the user can remove items from the app but still keep a record of them somewhere e.g., archive all tasks in the list into a file so that the user can start over with a clean slate.

C-MassOps

Mass operations

Provide a way to perform tasks on multiple items e.g., delete some specific items in one go.

C-Statistics

Statistics and insights

Provide a way to leverage statistics about the items managed by the App e.g., show the number of tasks that have been completed in the past week.

C-FriendlierSyntax

Friendlier syntax for commands

Make the command syntax more flexible.

Minimal: provide shorter aliases for keywords e.g., t can be shorter alias for todo.

Other ideas:

  • Allow users to define their own aliases
  • Remove the need for the parts of a command to be in a specific order

Extensions: Category D

D-Contacts

Support managing contacts

Support managing info about contacts e.g., details of friends

D-Notes

Support managing notes

Support managing info about small snippets of textual information the user wants to record e.g., one's own waist size, a name of a movie that the user wants to remember

D-Expenses

Support managing expenses

Support managing info about expenses e.g., the amounts spent on food, books, transport, etc.

D-Loans

Support managing loan records

Support keeping records of loans given/taken e.g., money lent/owed to colleagues/friends

D-Places

Support managing info about places

Support recording info about places e.g., info about restaurants visited, for future reference

D-Trivia

Support managing trivia

Provide the ability to learn/memorize thingse.g., learn vocabulary, answers to questions

D-Clients

Support managing client info

Support managing info about clients e.g., for an insurance agent to keep track of clients

D-Merchandise

Support managing merchandise info

Support managing info about merchandise e.g., a property agent to keep track of properties, a collector of stamps keep track of items in the collection