3.14 Libraries: Homework Notebook

Lesson: CSP 3.14 Libraries (School Basketball Season Stats App) Contents: Popcorn Hack 1 (read the API, then use it), Popcorn Hack 2 (write a Flask route), Homework Hack (Season Stats Report), submission notes.

Every code cell keeps # CODE_RUNNER: as its first line and only uses standard-library modules or flask.

Popcorn Hack 1: Read the API, Then Use It

What I changed: the jersey range is now 1-55, and I take the square root of a 225 sq ft court instead of 144.

Predictions (before running):

  • Jersey number: a whole number from 1 to 55, both included.
  • math.sqrt(225) = 15.0 feet.
  • Average of [24, 18, 31, 27, 22] = 122 / 5 = 24.4, and math.ceil(24.4) = 25.
  • random.choice returns one of 24, 18, 31, 27, or 22 (it changes every run).

Code Runner Challenge

Popcorn Hack 1 - jersey range changed to 1-55, new court size

View IPYNB Source
# CODE_RUNNER: Popcorn Hack 1 - jersey range changed to 1-55, new court size
import math
import random

# Read the API before calling a procedure
print("random.randint:", random.randint.__doc__)
print("math.ceil:", math.ceil.__doc__)
print("math has", len(dir(math)), "names; random has", len(dir(random)), "names")

points_per_game = [24, 18, 31, 27, 22]

# random.choice picks one item out of a list
print("Random game to review:", random.choice(points_per_game), "points")

# CHANGED: jersey numbers now run from 1 to 55 (both included)
jersey = random.randint(1, 55)
print("Random jersey number:", jersey)

# CHANGED: a 225 square foot court instead of 144
side = math.sqrt(225)
print("Square court side:", side, "feet")

# math.ceil rounds up to the next whole number
average = sum(points_per_game) / len(points_per_game)
rounded_up = math.ceil(average)
print("Points per game:", average, "-> rounded up:", rounded_up)
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Check: the printed Square court side is 15.0, the average is 24.4 and rounds up to 25, and the jersey number is always between 1 and 55, matching my predictions. Reading help/__doc__ first told me randint(a, b) includes both endpoints, so I didn’t have to know how it works inside. That’s abstraction.

Popcorn Hack 2: Write a Flask Route

My extra route: /coach (plus a /record route). I also put my own players in the roster.

Prediction: /score, /roster, /coach, and /record should each return the dictionary I pass to jsonify, as JSON. Routes are defined above app.test_client().

Code Runner Challenge

Popcorn Hack 2 - own roster plus /coach and /record routes

View IPYNB Source
# CODE_RUNNER: Popcorn Hack 2 - own roster plus /coach and /record routes
#!pip install flask
from flask import Flask, jsonify

app = Flask(__name__)

# A route is a procedure with a web address attached to it
@app.route("/score")
def score():
    return jsonify({"home": 58, "away": 52, "quarter": 3})

@app.route("/roster")
def roster():
    return jsonify({"players": ["Alex", "Jordan", "Priya", "Marcus"]})

# MY EXTRA ROUTES (copying the same pattern)
@app.route("/coach")
def coach():
    return jsonify({"coach": "Coach Rivera", "assistant": "Coach Lee"})

@app.route("/record")
def record():
    return jsonify({"wins": 6, "losses": 2})

# test_client visits the addresses without needing a browser
client = app.test_client()
print("/score says:", client.get("/score").get_json())
print("/roster says:", client.get("/roster").get_json())
print("/coach says:", client.get("/coach").get_json())
print("/record says:", client.get("/record").get_json())
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Three Ways to Import (code example)

Not required for submission, but I fixed the line that breaks when statistics is nicknamed s/stats.

Code Runner Challenge

Three ways to import - nickname stats

View IPYNB Source
# CODE_RUNNER: Three ways to import - nickname stats
import math                    # whole library: math. prefix required
from random import randint     # one procedure: no prefix
import statistics as stats     # nickname: stats stands in for statistics

print("Hoop circumference:", round(2 * math.pi * 0.75, 2), "feet")
print("Coin toss, 1 means home ball:", randint(1, 2))
print("Points per game:", stats.mean([24, 18, 31]))   # fixed: stats.mean, not statistics.mean
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Homework Hack: Season Stats Report

My own version: it uses four standard-library modules (json, statistics, datetime, math), a documented summarize_season procedure, datetime for the days until my next game, and a requirements.txt string. Replace the sample games and next-game date below with your own sport and schedule before you submit.

Code Runner Challenge

Homework Hack - Season Stats Report

View IPYNB Source
# CODE_RUNNER: Homework Hack - Season Stats Report
import json
import math
import statistics
from datetime import date

# Own games for the season (swap in your sport and your real results)
games = [
    {"date": "2026-09-05", "opponent": "Jefferson", "points": 19, "minutes": 24},
    {"date": "2026-09-12", "opponent": "Kennedy", "points": 27, "minutes": 29},
    {"date": "2026-09-19", "opponent": "Jefferson", "points": 22, "minutes": 26},
    {"date": "2026-09-26", "opponent": "Adams", "points": 33, "minutes": 31},
    {"date": "2026-09-29", "opponent": "Kennedy", "points": 15, "minutes": 20},
]


def summarize_season(season):
    """
    Summarize a list of games.

    Parameters:
        season: list of dictionaries, each with "date" (str), "opponent" (str),
                "points" (int), and "minutes" (int)

    Returns:
        dictionary with
            total_points (int): sum of all points scored,
            average_points (float): mean points per game, rounded to 1 decimal,
            best_game (int): the highest single-game point total,
            points_by_opponent (dict): total points scored against each opponent,
            points_per_minute (float): total points divided by total minutes, 2 decimals
    """
    points = [game["points"] for game in season]
    minutes = [game["minutes"] for game in season]

    points_by_opponent = {}
    for game in season:
        opponent = game["opponent"]
        points_by_opponent[opponent] = points_by_opponent.get(opponent, 0) + game["points"]

    return {
        "total_points": sum(points),
        "average_points": round(statistics.mean(points), 1),
        "best_game": max(points),
        "points_by_opponent": points_by_opponent,
        "points_per_minute": round(sum(points) / sum(minutes), 2),
    }


report = summarize_season(games)
# math.ceil rounds the average up: handy for a "scoring goal" on the scoreboard
report["next_scoring_goal"] = math.ceil(report["average_points"])

# Subtracting two dates returns a timedelta, and .days is the whole number of days
next_game = date(2026, 10, 17)
report["days_until_next_game"] = (next_game - date.today()).days
print(json.dumps(report, indent=2))

# requirements.txt lists only EXTERNAL packages (pandas for the season table, Flask for the
# scoreboard page). json, datetime, statistics, and math come with Python's standard library,
# so pip never needs to install them and they are never listed.
requirements_txt = """pandas
Flask
"""
print()
print("requirements.txt:")
print(requirements_txt)
Lines: 1 Characters: 0
Output
Click "Run" in code control panel to see output ...

Libraries used and why

  • json: json.dumps(report, indent=2) turns the Python dictionary into JSON text that a scoreboard page could read.
  • statistics: statistics.mean replaces my own add-and-divide loop with a tested procedure.
  • datetime: date(...) - date.today() gives a timedelta; .days is the whole number of days until the next game.
  • math: math.ceil rounds the average up for a scoring goal.
  • API documentation: the docstring on summarize_season lists each parameter and every key in the returned dictionary, so someone can use it without reading the code.
  • requirements.txt: pandas and Flask are external (installed with pip install -r requirements.txt); the four modules above are standard library, so they are never listed.

Submission Notes (paste into the description box)

Lesson: CSP 3.14 Libraries
Popcorn 1: what I changed = jersey range 1-55 and a 225 sq ft court (sqrt = 15.0)
Popcorn 2: my extra route = /coach (and /record)
Homework: libraries used = json, statistics, datetime (plus math)
Homework: days until my next game = see the printed days_until_next_game value (next game 2026-10-17)

The days_until_next_game value depends on the day you run the cell, so copy the number from your own run.