Holiday Film Matchmaker

Build a Python CLI that recommends holiday films from user preferences.

Introduction

30 Second Summary

Choosing a holiday film can take longer than watching the opening credits. Everyone has a different mood or amount of free time.

In this project, you will build a holiday film matchmaker with Python. You will answer three questions to get a recommendation from a list of fictional films.

What You'll Build

Picture running your matchmaker for friends and watching it pick a film that fits their mood, available time, and audience.

By the end of this project, you'll have:

  • An interactive film matcher that asks for a mood and immediately prints a holiday film recommendation.
  • A friendlier input experience that understands capital letters, extra spaces, and a second word for a funny mood.
  • A multi-question decision tree that considers viewing time and whether children are watching before choosing a film.
  • Secret Mission: Let one decision branch choose randomly between two suitable films.

Are there any prerequisites?

You need a Mac running macOS 10.15 or later.

You also need permission to install Python on your Mac.

Before We Start

A clear audience gives every comparison in your Holiday Film Matchmaker a purpose. This checkpoint helps you commit to who could use it and what film choice it helps them make.

Install Python and Configure VS Code

Visual Studio Code can edit your matcher file. It needs a separate Python interpreter before it can run your decisions.

The Python extension for Visual Studio Code connects the editor to that interpreter. You will prove the connection by running a starter program in a fresh terminal.

In this step, get ready to:
  • Prepare Python 3.15.2 for local development.
  • Configure VS Code with the Microsoft Python extension.
  • Prove the setup by running your starter file.
Install Python on your Mac

The Python.org installer used in this project supports macOS 10.15 or later. Checking your Mac first confirms that the installer can run on your system.

  • Click the Apple menu in the top-left corner of your screen.
  • Select About This Mac.
  • Confirm that the displayed macOS version is 10.15 or later.
  • Press Cmd+Space to open Spotlight.
  • Type Terminal.
  • Press Enter to open Terminal.
  • Check whether Python is already available by running this command:
python3 --version

What Does This Command Check?

  • The python3 command starts the Python 3 interpreter available to your terminal.
  • The --version option asks that interpreter to print its version.

✔️ I see the required version

Good news. Your Mac already has the exact interpreter this project needs.

  • Press Cmd+Space to open Spotlight.
  • Type Finder.
  • Press Enter to open Finder.
  • Open the Applications folder.
  • Open the Python 3.15 folder.
  • Double-click Install Certificates.command.

The certificate process is complete when the terminal shows Successfully installed certifi followed by update complete.

ⓧ I see an older version

The installed interpreter is older than the project version. The Python.org installer adds the required release to your Mac.

  • Open the Python.org macOS releases page in your browser.
  • Select the Python 3.15.2 release.
  • Download the macOS installer listed for that release.
  • Open the downloaded .pkg installer.
  • Select Continue through the installer screens.
  • Accept the software licence.
  • Choose the standard installation.
  • Complete the installation.

Your Mac now has Python 3.15.2 installed.

  • Press Cmd+Space to open Spotlight.
  • Type Finder.
  • Press Enter to open Finder.
  • Open the Applications folder.
  • Open the Python 3.15 folder.
  • Double-click Install Certificates.command.

The certificate process is complete when the terminal shows Successfully installed certifi followed by update complete.

ⓧ Python is not installed

Your Mac needs the Python.org package before VS Code can run the matcher. The installer provides the interpreter as a standard macOS application package.

  • Open the Python.org macOS releases page in your browser.
  • Select the Python 3.15.2 release.
  • Download the macOS installer listed for that release.
  • Open the downloaded .pkg installer.
  • Select Continue through the installer screens.
  • Accept the software licence.
  • Choose the standard installation.
  • Complete the installation.

Your Mac now has Python 3.15.2 installed.

  • Press Cmd+Space to open Spotlight.
  • Type Finder.
  • Press Enter to open Finder.
  • Open the Applications folder.
  • Open the Python 3.15 folder.
  • Double-click Install Certificates.command.

The certificate process is complete when the terminal shows Successfully installed certifi followed by update complete.

Cannot Find the Certificate Script?

  • Check that you opened /Applications/Python 3.15/Install Certificates.command from the main Applications folder.
  • Run the Python.org installer again if the Python 3.15 folder is missing.

Need help completing the Python installation?

Configure VS Code with the Python extension

The extension adds Python commands to VS Code. Selecting an interpreter tells those commands which Python installation to use.

  • Press Cmd+Space to open Spotlight.
  • Type Visual Studio Code.
  • Press Enter to open it.

VS Code is ready for the extension that connects your editor to Python.

  • Select the Extensions view from the left sidebar.
  • Enter Python in the extension search field.
  • Select the Python extension published by Microsoft.
  • Open the extension's context menu.
  • Select Install Another Version.
  • Choose version 2026.10.0 from the available versions.

The extension details now show version 2026.10.0. Your editor has the Python features required for this project.

  • Press Cmd+Shift+P to open the Command Palette.
  • Enter Python: Select Interpreter.
  • Select Python: Select Interpreter from the results.
  • Choose the interpreter entry containing Python 3.15.2.

VS Code now uses Python 3.15.2 for this workspace. The interpreter selection connects your run commands to the required installation.

Cannot Select the Required Interpreter?

  • Confirm that the extension details show version 2026.10.0.
  • Restart VS Code if Python 3.15.2 does not appear in the interpreter list.
  • Run Python: Select Interpreter again after VS Code restarts.

Help me connect VS Code to the correct Python interpreter.

Create and run the starter program

A file ending in .py is treated as a Python program. Your project folder keeps that file separate from unrelated work.

  • Click File in the VS Code menu bar.
  • Click Open Folder.
  • Select your Desktop in the folder dialog.
  • Use the new-folder control at the bottom of the dialog.
  • Enter holiday-film-matchmaker as the folder name.
  • Select the holiday-film-matchmaker folder.
  • Click Open to use it as your VS Code workspace.

You should see holiday-film-matchmaker at the top of the Explorer sidebar. This confirms that VS Code opened the correct folder.

  • Select the new-file icon in the Explorer sidebar.
  • Enter holiday_film_picker.py as the file name.
  • Press Enter to create the file.
  • Add the starter program by pasting this line:
print("Holiday Film Matchmaker is ready!")

What Does This Code Do?

  • The print() function sends a message to the terminal.
  • The readiness message gives you a visible test for the interpreter connection.
  • Press Cmd+S to save holiday_film_picker.py.

Your starter file should now contain one saved line. Use the reference tab if you want to compare the complete file.

✔️ Awesome, I've got everything!

Your starter file is complete. Keep holiday_film_picker.py open for the run check.

ⓧ I'd like to double check the full code

print("Holiday Film Matchmaker is ready!")

The final check uses VS Code's integrated terminal. A fresh terminal reads the interpreter choice you just configured.

  • Click Terminal in the VS Code menu bar.
  • Click New Terminal.

Before you run the check, do you think the fresh terminal will use the interpreter you selected?

  • Check the fresh terminal's Python version by running this command:
python3 --version

What Should You See?

The terminal should print Python 3.15.2. This confirms that the fresh terminal can access the required interpreter.

  • Press Cmd+Shift+P to open the Command Palette.
  • Enter Python: Run Python File in Terminal.
  • Select Python: Run Python File in Terminal from the results.

You should see Holiday Film Matchmaker is ready! beneath the earlier version output. That is the setup complete: VS Code is running your Python file with the selected interpreter.

Starter Message Missing?

  • Save holiday_film_picker.py before running it again.
  • Confirm that the file contains the exact print() line from the reference tab.
  • Run Python: Select Interpreter again if the terminal reports a different Python version.

Help me run my starter Python file in VS Code.

Your Python workspace is ready. Next up, you will turn this one-line test into your first working film decision.

Create Your First Film Decision

Your starter script proves that Visual Studio Code can run holiday_film_picker.py with the selected Python interpreter. A useful matcher now needs to turn one mood answer into one visible choice.

A decision tree checks comparisons in order to produce a recommendation immediately. Its exact string comparisons create a capitalization problem that you will uncover by testing it.

In this step, get ready to:
  • Store four film titles with their list positions.
  • Build a branch chain that chooses one recommendation.
  • Test how capitalization changes the branch that runs.
Build the mood decision tree

A list keeps the film titles in one ordered collection. An index lets each branch choose a title by position.

  • In holiday_film_picker.py, select the starter line print("Holiday Film Matchmaker is ready!").
  • Replace the selected line by pasting the complete decision tree below:
films = [
    "Snowy Short Stories",
    "The Great Gift Mix-Up",
    "North Pole Adventure",
    "Winter Wishes",
]

mood = input("Choose a mood: funny, cosy, or adventurous: ")

if mood == "funny":
    recommendation = films[1]
elif mood == "cosy":
    recommendation = films[3]
elif mood == "adventurous":
    recommendation = films[2]
else:
    recommendation = films[3]

print(f"Tonight's pick: {recommendation}")

What does this code do?

  • films stores four titles in an ordered list.
  • mood stores the string returned by input().
  • if starts the first comparison. Each elif checks another mood when an earlier comparison is false.
  • else provides a fallback recommendation when none of the named moods match.
  • The f-string places the chosen value inside the final message.
  • Save holiday_film_picker.py.

Before you run the new decision tree, predict which branch the answer funny reaches.

  • Run holiday_film_picker.py with Python: Run Python File in Terminal.
  • Type funny at the mood prompt.
  • Press Enter to submit the answer.

You'll see Tonight's pick: The Great Gift Mix-Up. That is your first live recommendation from a branch.

Don't see The Great Gift Mix-Up?

  • Check that you typed funny with lowercase letters at the prompt.
  • Confirm that recommendation = films[1] sits directly below if mood == "funny":.

Help me find why the funny branch is not running.

✔️ Awesome, I've got everything!

Your file now matches the complete mood decision tree.

ⓧ I'd like to double check the full code

films = [
    "Snowy Short Stories",
    "The Great Gift Mix-Up",
    "North Pole Adventure",
    "Winter Wishes",
]

mood = input("Choose a mood: funny, cosy, or adventurous: ")

if mood == "funny":
    recommendation = films[1]
elif mood == "cosy":
    recommendation = films[3]
elif mood == "adventurous":
    recommendation = films[2]
else:
    recommendation = films[3]

print(f"Tonight's pick: {recommendation}")
Trace the successful branch

Python checks this branch chain from top to bottom. It stops checking as soon as one condition is true.

  • In holiday_film_picker.py, locate if mood == "funny":.
  • Follow the next line to recommendation = films[1].
  • Count the films entries from index 0 to identify the title at index 1.
  • Compare that title with the terminal output from your funny run.

That trace is your first working decision path: funny leads from input() through == to films[1].

Test a capital letter

Your first run followed the intended lowercase path. The next run challenges the same decision tree with a slightly different input.

Before you run it again, predict whether Funny selects the same film as funny.

  • Run holiday_film_picker.py again with Python: Run Python File in Terminal.
  • Type Funny at the mood prompt.
  • Press Enter to submit the answer.

You'll see Tonight's pick: Winter Wishes. Every explicit mood comparison evaluates to False, so else assigns films[3].

That surprising fallback is the intended shortfall. Your program shows that Funny and funny are different strings during an exact comparison.

Don't see Winter Wishes?

  • Check that you entered Funny with a capital F.
  • Confirm that the quoted values in your if and elif conditions remain lowercase.

Help me trace why the capitalized answer reaches the fallback.

Your first decision tree is working. Next, you'll make its text matching handle capitalization and extra spaces.

Normalize Mood Input

Your first decision tree can recommend a film from a mood. The earlier Funny test exposed an exact-match problem.

String normalization prepares an answer before the decision tree compares it. The matcher will remove surrounding spaces with .strip().

It will convert letters to lowercase with .lower(). You will also accept silly as a second funny mood.

In this step, get ready to:
  • Normalize the mood answer before comparing it.
  • Accept a second funny mood with or.
  • Verify that both friendly input formats select the intended film.
Normalize the mood value

The input() function returns your answer as a string. Applying the two methods before assignment means mood always stores cleaned text.

  • In holiday_film_picker.py, find this line:
mood = input("Choose a mood: funny, cosy, or adventurous: ")

What does the current line store?

The current line stores the answer exactly as you type it. That raw value makes exact comparisons fragile.

  • Replace the line with this normalized version:
mood = input("Choose a mood: funny, cosy, or adventurous: ").strip().lower()

How does normalization work?

  • .strip() removes whitespace from the beginning or end of the answer.
  • .lower() converts cased letters to lowercase.
  • The chained result becomes the value stored in mood.

Before you run the updated matcher, do you think spaces or capital letters can still change the selected branch?

  • Save holiday_film_picker.py.
  • Run holiday_film_picker.py with Python: Run Python File in Terminal.
  • Enter Funny at the mood prompt.

You will see Tonight's pick: The Great Gift Mix-Up. That result proves the cleaned value reaches the funny branch.

Still seeing Winter Wishes?

  • Check that the mood input line ends with .strip().lower().
  • Make sure both method names include their parentheses.

Help me debug my normalized mood input.

Accept a second funny mood

A Boolean operator can combine multiple comparisons in one branch. The or operator makes the branch run when either comparison is true.

  • In holiday_film_picker.py, find this condition:
if mood == "funny":

What does the current condition accept?

The current condition recognizes only funny. Every other normalized word continues to the next branch.

  • Replace the condition with this combined comparison:
if mood == "funny" or mood == "silly":

What does the combined comparison do?

  • The first comparison checks for funny.
  • The second comparison checks for silly.
  • The or operator sends either value to the same recommendation.

Before you test the completed matcher, which branch do you expect both answers to reach?

  • Save holiday_film_picker.py.
  • Run holiday_film_picker.py with Python: Run Python File in Terminal.
  • Enter Funny at the mood prompt.

You will see Tonight's pick: The Great Gift Mix-Up.

  • Run holiday_film_picker.py again with Python: Run Python File in Terminal.
  • Enter silly at the mood prompt.

You will see Tonight's pick: The Great Gift Mix-Up again. Your matcher now handles both normalized formatting and a second funny-mood word.

Does silly reach the fallback?

  • Check that or appears between the two complete comparisons.
  • Check that the second comparison uses mood == "silly".
  • Make sure the combined condition ends with a colon.

Help me fix the silly mood comparison.

✔️ Awesome, I've got everything!

Your file now contains both text-comparison fixes.

ⓧ I'd like to double check the full code

films = [
    "Snowy Short Stories",
    "The Great Gift Mix-Up",
    "North Pole Adventure",
    "Winter Wishes",
]

mood = input("Choose a mood: funny, cosy, or adventurous: ").strip().lower()

if mood == "funny" or mood == "silly":
    recommendation = films[1]
elif mood == "cosy":
    recommendation = films[3]
elif mood == "adventurous":
    recommendation = films[2]
else:
    recommendation = films[3]

print(f"Tonight's pick: {recommendation}")

What should you compare?

Check that the mood input line ends with .strip().lower(). Check that the first branch accepts funny or silly.

Your matcher now understands friendly variations of the same mood. Next, you will combine mood with viewing time and audience preferences.

Build the Complete Matchmaker

Your matcher in Visual Studio Code now recognizes padded or capitalized mood answers. It also accepts the silly alias.

Mood alone cannot respect a short viewing window. It cannot account for children watching.

You will expand the Python decision tree with two more answers. Branch order turns those preferences into one recommendation.

In this step, get ready to:
  • Expand the film choices.
  • Collect the complete viewer profile.
  • Build a priority-based decision tree.
Complete the matchmaker's data

The finished matcher needs a fifth film for its cosy branch. Three answers provide enough information for the final decision tree.

  • In holiday_film_picker.py, select the existing films list.
  • Replace the selected list by pasting this code:
films = [
    "Snowy Short Stories",
    "The Great Gift Mix-Up",
    "North Pole Adventure",
    "Cosy Cocoa Christmas",
    "Winter Wishes",
]

What changed in the film list?

  • The films list now stores five titles.
  • The index films[3] now points to Cosy Cocoa Christmas.
  • The index films[4] now points to Winter Wishes.
  • The list order matters because each branch stores one indexed title in recommendation.
  • Save holiday_film_picker.py.
  • Run the file with Python: Run Python File in Terminal.
  • Enter cosy at the mood prompt.

You will see Tonight's pick: Cosy Cocoa Christmas. The new list position is working.

Still seeing the old cosy film?

  • Check that Cosy Cocoa Christmas is the fourth title in films.
  • Confirm that Winter Wishes is the fifth title.
  • Save holiday_film_picker.py before running it again.

Help me fix my updated film list.

The next update collects the available time as an integer. It also normalizes the audience answer before the decision tree reads it.

  • In holiday_film_picker.py, select the existing mood = input("Choose a mood: funny, cosy, or adventurous: ").strip().lower() line.
  • Replace the selected line by pasting this code:
print("Holiday Film Matchmaker")
print("Answer three questions to get tonight's recommendation.\n")

mood = input("Choose a mood: funny, cosy, or adventurous: ").strip().lower()
minutes = int(input("How many minutes do you have? ").strip())
children = input("Are children watching? yes or no: ").strip().lower()

What do these inputs collect?

  • The two print() calls introduce the matcher before the questions begin.
  • The mood value keeps its whitespace cleanup plus lowercase conversion.
  • The int() conversion turns the time answer into an integer for numeric comparisons.
  • The children value uses the same text normalization as the mood answer.
  • Save holiday_film_picker.py.
  • Run the file with Python: Run Python File in Terminal.
  • Enter funny for the mood.
  • Enter 100 for the available minutes.
  • Enter no for the audience answer.

You will see all three questions followed by Tonight's pick: The Great Gift Mix-Up. The matcher now collects the complete viewer profile.

Seeing an input problem?

  • Enter whole-number digits such as 100 at the minutes prompt.
  • Check that int() wraps the minutes input.
  • Confirm that every opening parenthesis has a matching closing parenthesis.

Help me troubleshoot the three matchmaker inputs.

Combine preferences in the decision tree

Compound conditions let one branch compare more than one preference. Branch order decides which valid rule receives priority.

  • In holiday_film_picker.py, select the branch chain starting with if mood == "funny" or mood == "silly":.
  • Extend the selection through the final recommendation line above print(f"Tonight's pick: {recommendation}").
  • Replace the selected branch chain by pasting this code:
if minutes < 80:
    recommendation = films[0]
elif children == "yes" and mood == "adventurous":
    recommendation = films[2]
elif mood == "funny" or mood == "silly":
    recommendation = films[1]
elif mood == "cosy" and minutes <= 100:
    recommendation = films[3]
else:
    recommendation = films[4]

How does the decision tree choose?

  • The minutes < 80 comparison gives a short viewing window the highest priority.
  • The children branch requires children == "yes" plus mood == "adventurous" to be true.
  • The funny branch accepts either funny or silly.
  • The cosy branch uses minutes <= 100 to include a viewing window of exactly 100 minutes.
  • The else branch provides Winter Wishes when no earlier condition is true.
  • Save holiday_film_picker.py.

Before you run the completed tree, picture the branch that adventurous, 100, plus yes will reach.

  • Run the file with Python: Run Python File in Terminal.
  • Enter adventurous for the mood.
  • Enter 100 for the available minutes.
  • Enter yes for the audience answer.

You have the full three-answer path working. The terminal prints Tonight's pick: North Pole Adventure.

Got a different recommendation?

  • Check that the children branch appears immediately after the short viewing branch.
  • Confirm that the children branch uses and between its two comparisons.
  • Check that the branch assigns films[2] to recommendation.

Help me trace the adventurous family branch.

✔️ Awesome, I've got everything!

Your completed file is saved. The final priority test is next.

ⓧ I'd like to double check the full code

films = [
    "Snowy Short Stories",
    "The Great Gift Mix-Up",
    "North Pole Adventure",
    "Cosy Cocoa Christmas",
    "Winter Wishes",
]

print("Holiday Film Matchmaker")
print("Answer three questions to get tonight's recommendation.\n")

mood = input("Choose a mood: funny, cosy, or adventurous: ").strip().lower()
minutes = int(input("How many minutes do you have? ").strip())
children = input("Are children watching? yes or no: ").strip().lower()

if minutes < 80:
    recommendation = films[0]
elif children == "yes" and mood == "adventurous":
    recommendation = films[2]
elif mood == "funny" or mood == "silly":
    recommendation = films[1]
elif mood == "cosy" and minutes <= 100:
    recommendation = films[3]
else:
    recommendation = films[4]

print(f"\nTonight's pick: {recommendation}")
Prove the first true branch wins

The final check reveals how an if chain behaves when several answers could support different films. Python evaluates branches from top to bottom.

Before the next run, predict which rule gets the first chance when the minutes value is 70.

  • Run the file with Python: Run Python File in Terminal.
  • Enter cosy for the mood.
  • Enter 70 for the available minutes.
  • Enter yes for the audience answer.

The terminal prints Tonight's pick: Snowy Short Stories. The first condition is true before Python reaches any mood or audience condition.

Why does 70 minutes take priority?

The comparison minutes < 80 is true when minutes contains 70. Python assigns films[0] to the recommendation.

Python stops after that first true branch. The remaining elif conditions do not run.

Did 70 minutes choose another film?

  • Confirm that if minutes < 80: is the first condition.
  • Check that this branch assigns films[0] to recommendation.
  • Verify that Snowy Short Stories remains the first title in films.

Help me trace the short viewing branch.

You did it. Your completed matchmaker now turns three answers into a prioritized recommendation.

Secret mission

Add Variety with Random Choice

Let the funny and cosy branches hold multiple suitable films. Then use random.choice() to vary the final recommendation while keeping every decision rule intact.

Clean Up Your Resources

Clean Up Your Resources

Your Python film matcher runs entirely on your Mac. There are no cloud services or ongoing costs.

Choose whether to keep the file, pause your work, or delete the file entirely.

Resources you used:

  • The local holiday_film_picker.py file containing your finished matcher.

Keep everything running

No action is needed. Choose this option while you want to keep testing your matcher.

  • Leave holiday_film_picker.py saved in its current location.
  • Return to the file whenever you want to test another set of answers.

Keeping this file has no financial cost.

Pause - I'll come back to this later

Pausing keeps your file while ending your current editing session.

  • Save holiday_film_picker.py.
  • Close Visual Studio Code.

Your program ends after it prints a recommendation. No background process keeps running.

  • Return to holiday_film_picker.py in Visual Studio Code when you are ready to continue.

Delete - I don't want to use this again

Removing the script is permanent. Choose this option only if you no longer want the matcher.

  • Switch back to the integrated terminal from earlier.
  • Remove holiday_film_picker.py by running this command:
rm holiday_film_picker.py

This shell command deletes only holiday_film_picker.py from the terminal's current folder.

  • Check the file sidebar in Visual Studio Code.

You should no longer see holiday_film_picker.py.

Still see the script?

  • Check that the integrated terminal from earlier still points to the folder containing holiday_film_picker.py.

Help me safely delete the project file.

Your Python installation and Visual Studio Code remain available for future projects.

Nice Work!

Nice Work!

You did it! You built an interactive holiday film matcher in Python that turns three viewer preferences into a recommendation.

You've learned how to:

  • Use list indexing to retrieve recommendations from a collection of fictional films.
  • Build a conditional decision tree with if, elif, and else branches.
  • Normalize text input with .strip().lower() so capital letters or extra spaces still reach the intended branch.
  • Secret Mission: Added controlled variety with random.choice() so suitable branches can recommend either of two films.

Ready to quiz yourself?