1
Python Programming
Assignment 5
Due not later than 11:59 PM on Sunday
On my honor as a student, I have neither given nor received any unauthorized aid on this
assignment/exam.
2
Program 1. Read and Write From a File
Question 1a: Code
#!/usr/bin/env python3
# Question 1a — Create two files:
# Imports
import sys # Platform-specific open/reveal
behavior
import os # Spawn OS-native open
from pathlib import Path # Cross-platform file handling
import tkinter as tk # Base Tkinter GUI toolkit
from tkinter import ttk, messagebox, simpledialog # Themed widgets
from typing import List # hints
import random # For "Append Random" name feature
# Visual theme
APP_TITLE = "Create Friends Files"
WINDOW_GEOMETRY = "860x560"
# Calm midnight palette
COL_BG = "#0b1b2b" # deep blue
COL_PANEL = "#0f2538" # panel blue
COL_TEXT = "#e6edf3" # light text
COL_MUTED = "#9fb3c8" # muted label
COL_PRIMARY = "#3fb7ff" # bright accent
COL_SECOND = "#c084fc" # violet accent
# Files & seed data
PATH_A = Path("[Link]") # must be < 5 names
PATH_B = Path("[Link]") # must be 5–7 names
SEED_A: List[str] = ["Noah", "Ada", "Mila", "Zane"] #
4 names
3
SEED_B: List[str] = ["Rowan", "Ivy", "Kai", "Serena", "Otis", "Leona"] #
6 names
# Pool for creative "Append Random" button
POOL_NAMES: List[str] = [
"Aria", "Theo", "Nova", "Jasper", "Elise", "Kian", "Mira", "Zuri",
"Felix", "Nya", "Hugo", "Ari", "Skye", "Enzo", "Lena", "Orion"
# Helper functions
# Create both files with their seed name sets
def create_or_overwrite_samples() -> None:
PATH_A.write_text("\n".join(SEED_A) + "\n", encoding="utf-8")
PATH_B.write_text("\n".join(SEED_B) + "\n", encoding="utf-8")
# Confirm both files are available
def ensure_samples_exist() -> None:
if not PATH_A.exists():
PATH_A.write_text("\n".join(SEED_A) + "\n", encoding="utf-8")
if not PATH_B.exists():
PATH_B.write_text("\n".join(SEED_B) + "\n", encoding="utf-8")
# Return the file contents as text
def read_text_or_hint(p: Path) -> str:
return p.read_text(encoding="utf-8") if [Link]() else f"{[Link]}
not found."
# Append a single name to file p
def append_single_name(p: Path, name: str) -> None:
current = p.read_text(encoding="utf-8").splitlines() if [Link]()
else []
[Link](name)
p.write_text("\n".join(current) + "\n", encoding="utf-8")
# Open the file Notepad Raises FileNotFoundError if no file
def open_with_default_app(p: Path) -> None:
4
if not [Link]():
raise FileNotFoundError(p)
if [Link]("win"):
[Link](p) # type: ignore[attr-defined]
elif [Link] == "darwin":
[Link](os.P_NOWAIT, "open", "open", str(p))
else:
[Link](os.P_NOWAIT, "xdg-open", "xdg-open", str(p))
# Reveal the file's folder
def reveal_in_explorer(p: Path) -> None:
folder = [Link]()
if [Link]("win"):
[Link](folder)
elif [Link] == "darwin":
[Link](os.P_NOWAIT, "open", "open", str(folder))
else:
[Link](os.P_NOWAIT, "xdg-open", "xdg-open", str(folder))
# UI components (custom)
# A [Link]
class AccentButton([Link]):
def __init__(self, master: [Link], **kwargs):
super().__init__(master, style="[Link]", **kwargs)
class Header([Link]): # Colorful section header
def __init__(self, master: [Link], text: str):
super().__init__(master, text=text, style="[Link]")
# Main window (distinct design)
# Two side panels for [Link] & [Link] with preview and
actions
class FriendsFilesApp([Link]):
5
def __init__(self) -> None:
super().__init__()
[Link](APP_TITLE)
[Link](WINDOW_GEOMETRY)
[Link](bg=COL_BG)
# ttk styles for the theme
style = [Link](self)
try:
style.theme_use("clam")
except [Link]:
pass
[Link](".", background=COL_BG, foreground=COL_TEXT)
[Link]("TFrame", background=COL_BG)
[Link]("TLabel", background=COL_BG, foreground=COL_TEXT)
[Link]("[Link]", foreground=COL_MUTED,
background=COL_BG)
[Link]("[Link]", font=("Segoe UI", 14, "bold"),
foreground=COL_PRIMARY, background=COL_BG)
[Link]("[Link]", padding=(10, 6), font=("Segoe
UI", 10, "bold"))
[Link]("[Link]",
foreground=[("!disabled", COL_TEXT)],
background=[("!disabled", COL_PRIMARY)])
[Link]("[Link]", padding=(8, 5))
[Link]("[Link]",
foreground=[("!disabled", COL_TEXT)],
background=[("!disabled", COL_SECOND)])
# Header text
Header(self, text="Create required friends
files").pack(anchor="w", padx=14, pady=(12, 6))
6
[Link](self, text="[Link] (<5 names) and [Link]
(5–7 names).",
style="[Link]").pack(anchor="w", padx=14,
pady=(0, 10))
# Action bar
bar = [Link](self); [Link](fill="x", padx=12, pady=(0, 10))
AccentButton(bar, text="Create / Overwrite Both",
command=self._make_both).pack(side="left")
[Link](bar, text="Create If Missing",
command=self._ensure_both, style="[Link]").pack(side="left", padx=8)
[Link](bar, text="Preview Both", command=self._preview_both,
style="[Link]").pack(side="left")
# Two panels
panels = [Link](self); [Link](fill="both", expand=True,
padx=12, pady=(0, 12))
self.left_panel = self._build_panel(panels, PATH_A, "[Link]
(must be < 5 names)")
self.right_panel = self._build_panel(panels, PATH_B,
"[Link] (must be 5–7 names)")
[Link](0, weight=1)
[Link](1, weight=1)
# Initial nudge
[Link](self, text="Tip: Click “Create / Overwrite Both”, then
Preview to verify.",
style="[Link]").pack(anchor="w", padx=14)
# panel builder
# panel for a single file with its controls and preview box.
def _build_panel(self, parent: [Link], path: Path, caption: str) -
> [Link]:
frame = [Link](parent)
col = 0 if path == PATH_A else 1
pad = (0, 10) if path == PATH_A else (10, 0)
[Link](row=0, column=col, sticky="nsew", padx=pad)
7
[Link](frame, text=caption, font=("Segoe UI", 11,
"bold")).pack(anchor="w", pady=(0, 6))
# Buttons row
row = [Link](frame); [Link](fill="x", pady=(0, 6))
[Link](row, text="Preview", command=lambda p=path:
self._preview(p), style="[Link]").pack(side="left")
[Link](row, text="Open Editor", command=lambda p=path:
self._open(p), style="[Link]").pack(side="left", padx=6)
[Link](row, text="Reveal Folder", command=lambda p=path:
self._reveal(p), style="[Link]").pack(side="left")
# Append row
add = [Link](frame); [Link](fill="x", pady=(6, 6))
[Link](add, text="Append Name…", command=lambda p=path:
self._append_manual(p)).pack(side="left")
[Link](add, text="Append Random", command=lambda p=path:
self._append_random(p)).pack(side="left", padx=6)
# Preview area
txt = [Link](frame, height=16, wrap="word", bg=COL_PANEL,
fg=COL_TEXT,
insertbackground=COL_TEXT, relief="flat")
[Link](fill="both", expand=True)
# Store reference
setattr(self, f"box_{'A' if path == PATH_A else 'B'}", txt)
return frame
# ---------- actions
# Create both files with the seed sets
def _make_both(self) -> None:
create_or_overwrite_samples()
[Link]("Created", "[Link] and [Link]
were (re)created.")
self._preview(PATH_A); self._preview(PATH_B)
# Confirm both files are present
8
def _ensure_both(self) -> None:
ensure_samples_exist()
[Link]("Ready", "Both files now exist. Existing
files were not changed.")
self._preview(PATH_A); self._preview(PATH_B)
# Load file text to preview box
def _preview(self, p: Path) -> None:
text = read_text_or_hint(p)
target = self.box_A if p == PATH_A else self.box_B
[Link]("1.0", "end")
[Link]("1.0", text)
# previews for both files
def _preview_both(self) -> None:
self._preview(PATH_A); self._preview(PATH_B)
# Prompt for a name and append
def _append_manual(self, p: Path) -> None:
name = [Link]("Append Name", f"Enter a name to
append to {[Link]}:")
if name:
append_single_name(p, [Link]())
self._preview(p)
# Append a random name from the pool
def _append_random(self, p: Path) -> None:
append_single_name(p, [Link](POOL_NAMES))
self._preview(p)
# Open file in the OS default
def _open(self, p: Path) -> None:
try:
open_with_default_app(p)
except Exception as e:
9
[Link]("Open Error", str(e))
# Reveal containing folder in the OS file explorer
def _reveal(self, p: Path) -> None:
try:
reveal_in_explorer(p)
except Exception as e:
[Link]("Reveal Error", str(e))
# Program Launcher
if __name__ == "__main__":
app = FriendsFilesApp()
[Link]()
Results
Question 1b
# Question 1b — Preview first five lines of a chosen file
# Imports
import sys
1
0
import os # Launch OS-native
open/explorer commands
from pathlib import Path # Cross-platform paths
import tkinter as tk # Tkinter GUI toolkit
from tkinter import ttk, filedialog, messagebox # Themed widgets +
dialogs
# Visual theme
APP_TITLE = "Preview First Five Lines"
WINDOW_GEOMETRY = "860x560"
COL_BG = "#0b1b2b" # deep blue
COL_PANEL = "#0f2538" # panel blue
COL_TEXT = "#e6edf3" # light text
COL_MUTED = "#9fb3c8" # muted label
COL_PRIMARY = "#3fb7ff" # bright accent
COL_SECOND = "#c084fc" # violet accent
# Offer quick choices that match Question 1a filenames
QUICK_FILES = ["[Link]", "[Link]"]
# Helper functions
def first_n_lines(p: Path, n: int = 5) -> str:
"""
Return up to the first n lines of a UTF-8 text file.
Args:
p: The file path to read.
n: Number of lines to preview (default 5; assignment requires 5).
Returns:
A string containing up to n lines joined by newlines, or a
friendly
message if the file is empty.
Raises:
FileNotFoundError: If the file does not exist.
1
1
UnicodeDecodeError: If the file is not UTF-8 decodable.
"""
if not [Link]():
raise FileNotFoundError(f"File not found: {p}")
lines = p.read_text(encoding="utf-8").splitlines()
if not lines:
return "(File is empty)"
return "\n".join(lines[:n])
# Compute simple metrics for a text file
# Return (line_count, char_count)
def file_metrics(p: Path) -> tuple[int, int]:
text = p.read_text(encoding="utf-8")
return (len([Link]()), len(text))
# Open the file
def open_with_default_app(p: Path) -> None:
if not [Link]():
raise FileNotFoundError(p)
if [Link]("win"):
[Link](p) # type: ignore[attr-defined]
elif [Link] == "darwin":
[Link](os.P_NOWAIT, "open", "open", str(p))
else:
[Link](os.P_NOWAIT, "xdg-open", "xdg-open", str(p))
# Open the OS file
def reveal_in_explorer(p: Path) -> None:
folder = [Link]()
if [Link]("win"):
[Link](folder)
elif [Link] == "darwin":
1
2
[Link](os.P_NOWAIT, "open", "open", str(folder))
else:
[Link](os.P_NOWAIT, "xdg-open", "xdg-open", str(folder))
# Small UI components
# colorful section header
class Header([Link]):
"""colorful section header."""
def __init__(self, master: [Link], text: str):
super().__init__(master, text=text, style="[Link]")
class AccentButton([Link]): # A [Link]
def __init__(self, master: [Link], **kwargs):
super().__init__(master, style="[Link]", **kwargs)
# Main window
class FirstFivePreviewApp([Link]):
"""
Main GUI:
• Filename entry with quick-pick dropdown and Browse…
• 'Preview First 5' button (assignment requirement)
• File metrics (line count, character count)
• Convenience actions: Open Editor, Reveal Folder, Clear
"""
def __init__(self) -> None:
super().__init__()
[Link](APP_TITLE)
[Link](WINDOW_GEOMETRY)
[Link](bg=COL_BG)
# ttk styles
style = [Link](self)
try:
1
3
style.theme_use("clam")
except [Link]:
pass
[Link](".", background=COL_BG, foreground=COL_TEXT)
[Link]("TFrame", background=COL_BG)
[Link]("TLabel", background=COL_BG, foreground=COL_TEXT)
[Link]("[Link]", foreground=COL_MUTED,
background=COL_BG)
[Link]("[Link]", font=("Segoe UI", 14, "bold"),
foreground=COL_PRIMARY, background=COL_BG)
[Link]("[Link]", padding=(10, 6), font=("Segoe
UI", 10, "bold"))
[Link]("[Link]",
foreground=[("!disabled", COL_TEXT)],
background=[("!disabled", COL_PRIMARY)])
[Link]("[Link]", padding=(8, 5))
[Link]("[Link]",
foreground=[("!disabled", COL_TEXT)],
background=[("!disabled", COL_SECOND)])
# Header
Header(self, text="Preview first five lines of a
file").pack(anchor="w", padx=14, pady=(12, 6))
[Link](self, text="Tip: Use the dropdown or Browse… to select
a file.",
style="[Link]").pack(anchor="w", padx=14,
pady=(0, 10))
# File selection row
select = [Link](self); [Link](fill="x", padx=12, pady=(0,
8))
[Link](select, text="File:").pack(side="left")
self.file_var = [Link](value=QUICK_FILES[0])
1
4
self.file_entry = [Link](select, textvariable=self.file_var,
width=52)
self.file_entry.pack(side="left", padx=6, fill="x", expand=True)
self.quick_combo = [Link](select, values=QUICK_FILES,
state="readonly", width=18)
self.quick_combo.set("Pick a sample…")
self.quick_combo.pack(side="left", padx=6)
self.quick_combo.bind("<<ComboboxSelected>>",
self._on_quick_pick)
[Link](select, text="Browse…", command=self._browse,
style="[Link]").pack(side="left")
# Actions row
actions = [Link](self); [Link](fill="x", padx=12,
pady=(0, 8))
AccentButton(actions, text="Preview First 5",
command=self._preview).pack(side="left")
[Link](actions, text="Open Editor",
command=self._open_editor, style="[Link]").pack(side="left", padx=6)
[Link](actions, text="Reveal Folder", command=self._reveal,
style="[Link]").pack(side="left")
[Link](actions, text="Clear", command=self._clear,
style="[Link]").pack(side="left", padx=6)
# Metrics panel
metrics = [Link](self); [Link](fill="x", padx=12,
pady=(0, 8))
self.lines_var = [Link](value="Lines: -")
self.chars_var = [Link](value="Characters: -")
[Link](metrics, textvariable=self.lines_var).pack(side="left",
padx=(0, 12))
[Link](metrics, textvariable=self.chars_var).pack(side="left")
# Output area
[Link] = [Link](self, height=22, wrap="word", bg=COL_PANEL,
fg=COL_TEXT,
1
5
insertbackground=COL_TEXT, relief="flat")
[Link](fill="both", expand=True, padx=12, pady=(0, 12))
# Footer note
[Link](self,
text="Assignment note: The preview shows only the first
five lines (or the entire file if <5).",
style="[Link]").pack(anchor="w", padx=14)
# Event handlers
# update the entry box
def _on_quick_pick(self, _event=None) -> None:
choice = self.quick_combo.get()
if choice:
self.file_var.set(choice)
# Open a platform-native file dialog
def _browse(self) -> None:
path = [Link](
title="Select a text file",
filetypes=[("Text Files", "*.txt"), ("All Files", "*.*")],
if path:
self.file_var.set(path)
# Read and display up to five lines; if the file has fewer than 5
lines,
# display the entire file. Also update metrics
def _preview(self) -> None:
try:
p = Path(self.file_var.get().strip())
1
6
text = first_n_lines(p, n=5) # requirement: five-line
preview
[Link]("1.0", "end")
[Link]("1.0", text)
# Update metrics
line_count, char_count = file_metrics(p)
self.lines_var.set(f"Lines: {line_count}")
self.chars_var.set(f"Characters: {char_count}")
except FileNotFoundError as e:
[Link]("Not Found", str(e))
except UnicodeDecodeError:
[Link]("Encoding Error", "Unable to decode file
as UTF-8.")
except Exception as exc:
[Link]("Error", str(exc))
# Open the selected file
def _open_editor(self) -> None:
try:
p = Path(self.file_var.get().strip())
open_with_default_app(p)
except Exception as exc:
[Link]("Open Error", str(exc))
# Reveal the selected file's folder in the OS file explorer
def _reveal(self) -> None:
try:
p = Path(self.file_var.get().strip())
reveal_in_explorer(p)
except Exception as exc:
[Link]("Reveal Error", str(exc))
# Clear the output and reset
1
7
def _clear(self) -> None:
[Link]("1.0", "end")
self.lines_var.set("Lines: -")
self.chars_var.set("Characters: -")
# Program Launcher
if __name__ == "__main__":
app = FirstFivePreviewApp()
[Link]()
Results
Program 2. Counting Names
Question 2a
# Question 2a — Create [Link] with the required 20 names
# Imports
1
8
import sys # For platform-specific
import os # For launching OS-native
from pathlib import Path # Cross-platform filesystem
paths
import tkinter as tk # Tkinter GUI toolkit
from tkinter import ttk, messagebox # Themed widgets + standard
dialogs
from typing import List # hints
import random # "Shuffle Preview"
# Visual Theme
APP_TITLE = "Create [Link] (20 Required Names)"
WINDOW_GEOMETRY = "820x560"
COL_BG = "#0b1b2b" # deep blue background
COL_PANEL = "#0f2538" # panel background
COL_TEXT = "#e6edf3" # light text
COL_MUTED = "#9fb3c8" # muted label text
COL_PRIMARY = "#3fb7ff" # bright accent
COL_SECOND = "#c084fc" # violet accent
# File Path & Required Data
NAMES_FILE = Path("[Link]") # must be created by this program
REQUIRED_NAMES: List[str] = [
"Liam", "Emma", "Noah", "Olivia", "William", "Ava", "James",
"Isabella",
"Oliver", "Sophia", "Benjamin", "Charlotte", "Elijah", "Mia",
"Lucas",
"Amelia", "Mason", "Harper", "Logan", "Evelyn"
# Helper Functions
def write_required_names(overwrite: bool = True) -> None:
"""
1
9
Write the exact required list to [Link].
Args:
overwrite: If True, always rewrite; if False, only create when
missing.
"""
if overwrite or not NAMES_FILE.exists():
NAMES_FILE.write_text("\n".join(REQUIRED_NAMES) + "\n",
encoding="utf-8")
# Return the contents of [Link]
def read_names_text() -> str:
return NAMES_FILE.read_text(encoding="utf-8") if NAMES_FILE.exists()
else "[Link] not found."
# Open the txt file
def open_with_default_app(p: Path) -> None:
if not [Link]():
raise FileNotFoundError(p)
if [Link]("win"):
[Link](p) # type: ignore[attr-defined]
elif [Link] == "darwin":
[Link](os.P_NOWAIT, "open", "open", str(p))
else:
[Link](os.P_NOWAIT, "xdg-open", "xdg-open", str(p))
# Reveal the containing folder
def reveal_in_explorer(p: Path) -> None:
folder = [Link]()
if [Link]("win"):
[Link](folder)
elif [Link] == "darwin":
[Link](os.P_NOWAIT, "open", "open", str(folder))
else:
2
0
[Link](os.P_NOWAIT, "xdg-open", "xdg-open", str(folder))
# UI Components
# header for visual hierarchy
class Header([Link]):
def __init__(self, master: [Link], text: str):
super().__init__(master, text=text, style="[Link]")
# A [Link]
class AccentButton([Link]):
def __init__(self, master: [Link], **kwargs):
super().__init__(master, style="[Link]", **kwargs)
# Main GUI Application
class NamesPadApp([Link]):
"""
Professional Tkinter app for Question 2a:
• "Write Required " — writes exactly the 20 names
• "Create If Missing" — writes only if [Link] doesn't exist.
• "Preview"
• Extras: Open Editor, Reveal Folder, Copy to Clipboard, Shuffle
Preview (display-only).
"""
def __init__(self) -> None:
super().__init__()
[Link](APP_TITLE)
[Link](WINDOW_GEOMETRY)
[Link](bg=COL_BG)
# ----- ttk styles for this theme
style = [Link](self)
try:
style.theme_use("clam")
2
1
except [Link]:
pass
[Link](".", background=COL_BG, foreground=COL_TEXT)
[Link]("TFrame", background=COL_BG)
[Link]("TLabel", background=COL_BG, foreground=COL_TEXT)
[Link]("[Link]", background=COL_BG,
foreground=COL_MUTED)
[Link]("[Link]", font=("Segoe UI", 14, "bold"),
foreground=COL_PRIMARY, background=COL_BG)
[Link]("[Link]", padding=(10, 6), font=("Segoe
UI", 10, "bold"))
[Link]("[Link]",
foreground=[("!disabled", COL_TEXT)],
background=[("!disabled", COL_PRIMARY)])
[Link]("[Link]", padding=(8, 5))
[Link]("[Link]",
foreground=[("!disabled", COL_TEXT)],
background=[("!disabled", COL_SECOND)])
# Header & tip
Header(self, text="Create [Link] with required
names").pack(anchor="w", padx=14, pady=(12, 6))
[Link](self, text="This tool writes exactly the 20-name list
specified in the assignment.",
style="[Link]").pack(anchor="w", padx=14,
pady=(0, 10))
# Action bar
actions = [Link](self); [Link](fill="x", padx=12,
pady=(0, 10))
AccentButton(actions, text="Write Required (Overwrite)",
command=self._write_overwrite).pack(side="left")
2
2
[Link](actions, text="Create If Missing",
command=self._create_if_missing, style="[Link]").pack(side="left",
padx=8)
[Link](actions, text="Preview", command=self._preview,
style="[Link]").pack(side="left")
# Extra utilities
utils = [Link](self); [Link](fill="x", padx=12, pady=(0,
6))
[Link](utils, text="Open Editor", command=self._open_editor,
style="[Link]").pack(side="left")
[Link](utils, text="Reveal Folder", command=self._reveal,
style="[Link]").pack(side="left", padx=6)
[Link](utils, text="Copy to Clipboard", command=self._copy,
style="[Link]").pack(side="left", padx=6)
[Link](utils, text="Shuffle Preview",
command=self._shuffle_preview, style="[Link]").pack(side="left")
# Output text area
[Link] = [Link](self, height=22, wrap="word", bg=COL_PANEL,
fg=COL_TEXT,
insertbackground=COL_TEXT, relief="flat")
[Link](fill="both", expand=True, padx=12, pady=(4, 12))
[Link](self, text="Note: 'Shuffle Preview' is for display only
— it does not change [Link].",
style="[Link]").pack(anchor="w", padx=14)
# Event Handlers
# Write the exact required list to [Link]
def _write_overwrite(self) -> None:
try:
write_required_names(overwrite=True)
[Link]("Done", "Wrote the required 20 names to
[Link].")
self._preview()
2
3
except Exception as exc:
[Link]("Error", str(exc))
# Create [Link] with the required
def _create_if_missing(self) -> None:
try:
write_required_names(overwrite=False)
[Link]("Ready", "Ensured [Link] exists with
the required names.")
self._preview()
except Exception as exc:
[Link]("Error", str(exc))
def _preview(self) -> None: # Load and show [Link]
[Link]("1.0", "end")
[Link]("1.0", read_names_text())
def _open_editor(self) -> None: # Open [Link]
try:
open_with_default_app(NAMES_FILE)
except Exception as exc:
[Link]("Open Error", str(exc))
# Reveal the folder where [Link] live
def _reveal(self) -> None:
try:
reveal_in_explorer(NAMES_FILE)
except Exception as exc:
[Link]("Reveal Error", str(exc))
def _copy(self) -> None: # Copy current preview text
try:
text = [Link]("1.0", "end").strip()
self.clipboard_clear()
2
4
self.clipboard_append(text)
[Link]("Copied", "Preview text copied to
clipboard.")
except Exception as exc:
[Link]("Copy Error", str(exc))
def _shuffle_preview(self) -> None: # Show a randomized order
shuffled = REQUIRED_NAMES[:]
[Link](shuffled)
[Link]("1.0", "end")
[Link]("1.0", "\n".join(shuffled))
# Program Launcher
if __name__ == "__main__":
app = NamesPadApp()
[Link]()
Results
2
5
Question2b
#!/usr/bin/env python3
# Question 2b — Count names in [Link]
# Imports (all commented)
import sys # Platform checks for
open/reveal
import os # Launch OS-native
open/explorer commands
from pathlib import Path # Cross-platform file paths
import tkinter as tk # Tkinter GUI toolkit
from tkinter import ttk, messagebox # Themed widgets + dialogs
# Visual theme
APP_TITLE = "Count Names in [Link]"
WINDOW_GEOMETRY = "780x520"
2
6
COL_BG = "#0b1b2b" # deep blue
COL_PANEL = "#0f2538" # panel blue
COL_TEXT = "#e6edf3" # light text
COL_MUTED = "#9fb3c8" # muted label
COL_PRIMARY = "#3fb7ff" # bright accent
COL_SECOND = "#c084fc" # violet accent
# File path
NAMES_FILE = Path("[Link]") # Created by 2a
# Core logic (exact spec)
# Count lines in a UTF-8 file using the priming-read + while approach
def count_names_priming_while(file_path: Path) -> int:
# a) Variables: counter and line sentinel
count = 0
line = '' # two single quotes = empty string (EOF sentinel)
# b) Open the file (manual open/close to mirror step e)
f = file_path.open("r", encoding="utf-8")
try:
# c) Priming read (read first line BEFORE the loop)
line = [Link]()
# d) While loop until there are no more lines
while line != '':
count += 1
line = [Link]()
finally:
# e) Close the file
[Link]()
# f) Return count so caller can display it
return count
# Helpers
2
7
# Return file contents
def read_names_text() -> str:
return NAMES_FILE.read_text(encoding="utf-8") if NAMES_FILE.exists()
else "[Link] not found. Run 2a first."
# Open the file in the system's default editor
def open_with_default_app(p: Path) -> None:
if not [Link]():
raise FileNotFoundError(p)
if [Link]("win"):
[Link](p) # type: ignore[attr-defined]
elif [Link] == "darwin":
[Link](os.P_NOWAIT, "open", "open", str(p))
else:
[Link](os.P_NOWAIT, "xdg-open", "xdg-open", str(p))
# Reveal the file’s folder
def reveal_in_explorer(p: Path) -> None:
folder = [Link]()
if [Link]("win"):
[Link](folder) # type: ignore[attr-defined]
elif [Link] == "darwin":
[Link](os.P_NOWAIT, "open", "open", str(folder))
else:
[Link](os.P_NOWAIT, "xdg-open", "xdg-open", str(folder))
# UI components
# header for visual hierarchy
class Header([Link]):
def __init__(self, master: [Link], text: str):
super().__init__(master, text=text, style="[Link]")
class AccentButton([Link]): # A [Link]
2
8
def __init__(self, master: [Link], **kwargs):
super().__init__(master, style="[Link]", **kwargs)
# Main GUI
class NamesCountApp([Link]):
"""
Professional GUI:
• 'Count Names' uses the priming-read + while logic
• 'Preview' shows the file
• Open Editor / Reveal Folder shortcuts
"""
def __init__(self) -> None:
super().__init__()
[Link](APP_TITLE)
[Link](WINDOW_GEOMETRY)
[Link](bg=COL_BG)
# Theme
style = [Link](self)
try:
style.theme_use("clam")
except [Link]:
pass
[Link](".", background=COL_BG, foreground=COL_TEXT)
[Link]("TFrame", background=COL_BG)
[Link]("TLabel", background=COL_BG, foreground=COL_TEXT)
[Link]("[Link]", foreground=COL_MUTED,
background=COL_BG)
[Link]("[Link]", font=("Segoe UI", 14, "bold"),
foreground=COL_PRIMARY, background=COL_BG)
[Link]("[Link]", padding=(10, 6), font=("Segoe
UI", 10, "bold"))
2
9
[Link]("[Link]",
foreground=[("!disabled", COL_TEXT)],
background=[("!disabled", COL_PRIMARY)])
[Link]("[Link]", padding=(8, 5))
[Link]("[Link]",
foreground=[("!disabled", COL_TEXT)],
background=[("!disabled", COL_SECOND)])
# Header
Header(self, text="Count names in [Link]").pack(anchor="w",
padx=14, pady=(12, 6))
[Link](self, text="Uses priming read + while loop (exact steps
a–f).",
style="[Link]").pack(anchor="w", padx=14,
pady=(0, 10))
# Action bar
actions = [Link](self); [Link](fill="x", padx=12,
pady=(0, 8))
AccentButton(actions, text="Count Names",
command=self._count).pack(side="left")
[Link](actions, text="Preview", command=self._preview,
style="[Link]").pack(side="left", padx=6)
[Link](actions, text="Open Editor",
command=self._open_editor, style="[Link]").pack(side="left")
[Link](actions, text="Reveal Folder", command=self._reveal,
style="[Link]").pack(side="left", padx=6)
# Result label
self.result_var = [Link](value="Total names: -")
[Link](self, textvariable=self.result_var, font=("Segoe UI",
11)).pack(anchor="w", padx=14, pady=(6, 6))
# Preview area
[Link](self, text="[Link] preview:").pack(anchor="w",
padx=14)
3
0
[Link] = [Link](self, height=18, wrap="word",
bg=COL_PANEL, fg=COL_TEXT,
insertbackground=COL_TEXT, relief="flat")
[Link](fill="both", expand=True, padx=12, pady=(2,
12))
[Link](self, text="Tip: Run 2a to create [Link] if it
doesn't exist.",
style="[Link]").pack(anchor="w", padx=14)
# handlers
# Count names and update the UI
def _count(self) -> None:
try:
if not NAMES_FILE.exists():
raise FileNotFoundError("[Link] not found. Please run
2a first.")
total = count_names_priming_while(NAMES_FILE)
self.result_var.set(f"Total names: {total}")
self._preview()
except Exception as exc:
[Link]("Error", str(exc))
# Show file contents
def _preview(self) -> None:
[Link]("1.0", "end")
[Link]("1.0", read_names_text())
# Open the txt file using notepad
def _open_editor(self) -> None:
try:
open_with_default_app(NAMES_FILE)
except Exception as exc:
[Link]("Open Error", str(exc))
3
1
# Reveal the file's folder
def _reveal(self) -> None:
try:
reveal_in_explorer(NAMES_FILE)
except Exception as exc:
[Link]("Reveal Error", str(exc))
# Program Launcher
if __name__ == "__main__":
app = NamesCountApp()
[Link]()
Results
Question 3. Getting a Total
Question 3a
3
2
#!/usr/bin/env python3
# Question 3a — Create [Link]
# Imports
import sys # Platform checks for
open/reveal actions
import os # Launch OS-native
from pathlib import Path # Cross-platform file paths
import tkinter as tk # Base Tkinter GUI toolkit
from tkinter import ttk, messagebox # Themed widgets and dialogs
from typing import List # hints
# Visual Theme
APP_TITLE = "Create [Link] (Required Integers)"
WINDOW_GEOMETRY = "740x500"
COL_BG = "#0b1b2b" # deep blue
COL_PANEL = "#0f2538" # panel blue
COL_TEXT = "#e6edf3" # light text
COL_MUTED = "#9fb3c8" # muted label
COL_PRIMARY = "#3fb7ff" # bright accent
COL_SECOND = "#c084fc" # violet accent
# File Path & Required Data
NUMBERS_FILE = Path("[Link]") # File to create
REQUIRED_NUMBERS: List[int] = [75, 63, -8, -99]
# Helper Functions (each documented)
def write_required_numbers(overwrite: bool = True) -> None:
if overwrite or not NUMBERS_FILE.exists():
text = "\n".join(str(n) for n in REQUIRED_NUMBERS) + "\n"
NUMBERS_FILE.write_text(text, encoding="utf-8")
def read_numbers_text() -> str: # Return [Link]
3
3
return NUMBERS_FILE.read_text(encoding="utf-8") if
NUMBERS_FILE.exists() else "[Link] not found."
def open_with_default_app(p: Path) -> None:
"""
Open the file in the system's default editor
Else, FileNotFoundError
"""
if not [Link]():
raise FileNotFoundError(p)
if [Link]("win"):
[Link](p) # type: ignore[attr-defined]
elif [Link] == "darwin":
[Link](os.P_NOWAIT, "open", "open", str(p))
else:
[Link](os.P_NOWAIT, "xdg-open", "xdg-open", str(p))
def reveal_in_explorer(p: Path) -> None: # Reveal file's folder
folder = [Link]()
if [Link]("win"):
[Link](folder) # type: ignore[attr-defined]
elif [Link] == "darwin":
[Link](os.P_NOWAIT, "open", "open", str(folder))
else:
[Link](os.P_NOWAIT, "xdg-open", "xdg-open", str(folder))
# Small UI Components
# header for visual hierarchy
class Header([Link]):
def __init__(self, master: [Link], text: str):
super().__init__(master, text=text, style="[Link]")
class AccentButton([Link]): # A [Link]
3
4
def __init__(self, master: [Link], **kwargs):
super().__init__(master, style="[Link]", **kwargs)
# Main GUI Application
class NumbersPadApp([Link]):
"""
Professional Tkinter app for Question 3a:
• "Write Required (Overwrite)
• "Create If Missing"
• "Preview"
• Utilities: Open Editor, Reveal Folder, Clear.
"""
def __init__(self) -> None:
super().__init__()
[Link](APP_TITLE)
[Link](WINDOW_GEOMETRY)
[Link](bg=COL_BG)
# -ttk styles
style = [Link](self)
try:
style.theme_use("clam")
except [Link]:
pass
[Link](".", background=COL_BG, foreground=COL_TEXT)
[Link]("TFrame", background=COL_BG)
[Link]("TLabel", background=COL_BG, foreground=COL_TEXT)
[Link]("[Link]", background=COL_BG,
foreground=COL_MUTED)
[Link]("[Link]", font=("Segoe UI", 14, "bold"),
foreground=COL_PRIMARY, background=COL_BG)
3
5
[Link]("[Link]", padding=(10, 6), font=("Segoe
UI", 10, "bold"))
[Link]("[Link]",
foreground=[("!disabled", COL_TEXT)],
background=[("!disabled", COL_PRIMARY)])
[Link]("[Link]", padding=(8, 5))
[Link]("[Link]",
foreground=[("!disabled", COL_TEXT)],
background=[("!disabled", COL_SECOND)])
# Header & tip
Header(self, text="Create [Link] with required
integers").pack(anchor="w", padx=14, pady=(12, 6))
[Link](self, text="Writes exactly 75, 63, -8, and -99 (one per
line).",
style="[Link]").pack(anchor="w", padx=14,
pady=(0, 10))
# Action bar
actions = [Link](self); [Link](fill="x", padx=12,
pady=(0, 10))
AccentButton(actions, text="Write Required (Overwrite)",
command=self._write_overwrite).pack(side="left")
[Link](actions, text="Create If Missing",
command=self._create_if_missing, style="[Link]").pack(side="left",
padx=8)
[Link](actions, text="Preview", command=self._preview,
style="[Link]").pack(side="left")
# Utilities
utils = [Link](self); [Link](fill="x", padx=12, pady=(0,
6))
[Link](utils, text="Open Editor", command=self._open_editor,
style="[Link]").pack(side="left")
[Link](utils, text="Reveal Folder", command=self._reveal,
style="[Link]").pack(side="left", padx=6)
3
6
[Link](utils, text="Clear Preview", command=self._clear,
style="[Link]").pack(side="left", padx=6)
# Output text area
[Link] = [Link](self, height=18, wrap="word", bg=COL_PANEL,
fg=COL_TEXT,
insertbackground=COL_TEXT, relief="flat")
[Link](fill="both", expand=True, padx=12, pady=(4, 12))
[Link](self, text="Note: 3b will read this file and compute
the total.",
style="[Link]").pack(anchor="w", padx=14)
# Event Handlers
# required list to [Link]
def _write_overwrite(self) -> None:
try:
write_required_numbers(overwrite=True)
[Link]("Done", "Wrote the required integers to
[Link].")
self._preview()
except Exception as exc:
[Link]("Error", str(exc))
def _create_if_missing(self) -> None: # Create [Link]
try:
write_required_numbers(overwrite=False)
[Link]("Ready", "Ensured [Link] exists with
the required integers.")
self._preview()
except Exception as exc:
[Link]("Error", str(exc))
def _preview(self) -> None: # Load and show [Link]
[Link]("1.0", "end")
3
7
[Link]("1.0", read_numbers_text())
def _open_editor(self) -> None: # Open [Link]
try:
open_with_default_app(NUMBERS_FILE)
except Exception as exc:
[Link]("Open Error", str(exc))
def _reveal(self) -> None: # Reveal the file's folder
try:
reveal_in_explorer(NUMBERS_FILE)
except Exception as exc:
[Link]("Reveal Error", str(exc))
def _clear(self) -> None: # Clear the preview
[Link]("1.0", "end")
# Program Launcher
if __name__ == "__main__":
app = NumbersPadApp()
[Link]()
Results
3
8
Question 3b
#!/usr/bin/env python3
# Question 3b — Read [Link] and output the total
# Imports (
3
9
import sys # Platform checks for
open/reveal
import os # Launch OS-native
from pathlib import Path # Cross-platform file
handling
import tkinter as tk # Base Tkinter GUI toolkit
from tkinter import ttk, messagebox # Themed widgets + dialogs
# Visual theme
APP_TITLE = "Total of [Link] (Priming Read + FOR)"
WINDOW_GEOMETRY = "780x520"
COL_BG = "#0b1b2b" # deep blue
COL_PANEL = "#0f2538" # panel blue
COL_TEXT = "#e6edf3" # light text
COL_MUTED = "#9fb3c8" # muted label
COL_PRIMARY = "#3fb7ff" # bright accent
COL_SECOND = "#c084fc" # violet accent
# File path
NUMBERS_FILE = Path("[Link]") # Created by Question 3a
# Core logic (ex
def compute_total_priming_for(file_path: Path) -> float:
"""
Compute the total of all numeric lines in [Link] using:
- 'line' sentinel (initialized to '')
- 'number' as float
- priming read for the first row
- FOR loop for remaining rows
- explicit close at the end
Returns:
The total as a float.
"""
4
0
# a) Create 'line' and set to empty string
line: str = ''
# b) Create 'number' as float
number: float = 0.0
# c) Create 'total'
total: float = 0.0
# Open the file
f = file_path.open("r", encoding="utf-8")
try:
# d) Priming read: read the first row BEFORE the loop
line = [Link]()
# If we actually got a line, process it
if line != '':
stripped = [Link]()
if stripped != '':
number = float(stripped) # ensure float datatype
total += number
# d) FOR loop to process remaining lines
for line in f:
stripped = [Link]()
if stripped == '':
continue # skip blank lines safely (optional)
number = float(stripped) # ensure float datatype
total += number
finally:
# e) Close the file
[Link]()
# f) Return result so caller can display it
return total
4
1
# Helpers (UI convenience)
# Return [Link] contents
def read_numbers_text() -> str:
return NUMBERS_FILE.read_text(encoding="utf-8") if
NUMBERS_FILE.exists() else "[Link] not found. Run 3a first."
def open_with_default_app(p: Path) -> None: # Open file
if not [Link]():
raise FileNotFoundError(p)
if [Link]("win"):
[Link](p) # type: ignore[attr-defined]
elif [Link] == "darwin":
[Link](os.P_NOWAIT, "open", "open", str(p))
else:
[Link](os.P_NOWAIT, "xdg-open", "xdg-open", str(p))
def reveal_in_explorer(p: Path) -> None: # Reveal file's folder
folder = [Link]()
if [Link]("win"):
[Link](folder) # type: ignore[attr-defined]
elif [Link] == "darwin":
[Link](os.P_NOWAIT, "open", "open", str(folder))
else:
[Link](os.P_NOWAIT, "xdg-open", "xdg-open", str(folder))
# UI components
# header for visual hierarchy
class Header([Link]):
def __init__(self, master: [Link], text: str):
super().__init__(master, text=text, style="[Link]")
class AccentButton([Link]): # A [Link]
def __init__(self, master: [Link], **kwargs):
4
2
super().__init__(master, style="[Link]", **kwargs)
# Main GUI
class NumbersTotalApp([Link]):
"""
Professional GUI:
• 'Compute Total' uses priming read + FOR loop logic
• 'Preview' shows [Link]
• Shortcuts: Open Editor, Reveal Folder
"""
def __init__(self) -> None:
super().__init__()
[Link](APP_TITLE)
[Link](WINDOW_GEOMETRY)
[Link](bg=COL_BG)
# Theme
style = [Link](self)
try:
style.theme_use("clam")
except [Link]:
pass
[Link](".", background=COL_BG, foreground=COL_TEXT)
[Link]("TFrame", background=COL_BG)
[Link]("TLabel", background=COL_BG, foreground=COL_TEXT)
[Link]("[Link]", foreground=COL_MUTED,
background=COL_BG)
[Link]("[Link]", font=("Segoe UI", 14, "bold"),
foreground=COL_PRIMARY, background=COL_BG)
[Link]("[Link]", padding=(10, 6), font=("Segoe
UI", 10, "bold"))
[Link]("[Link]",
4
3
foreground=[("!disabled", COL_TEXT)],
background=[("!disabled", COL_PRIMARY)])
[Link]("[Link]", padding=(8, 5))
[Link]("[Link]",
foreground=[("!disabled", COL_TEXT)],
background=[("!disabled", COL_SECOND)])
# Header
Header(self, text="Compute total of
[Link]").pack(anchor="w", padx=14, pady=(12, 6))
[Link](self, text="Uses priming read + FOR loop (steps a–f).",
style="[Link]").pack(anchor="w", padx=14,
pady=(0, 10))
# Action bar
actions = [Link](self); [Link](fill="x", padx=12,
pady=(0, 8))
AccentButton(actions, text="Compute Total",
command=self._compute).pack(side="left")
[Link](actions, text="Preview", command=self._preview,
style="[Link]").pack(side="left", padx=6)
[Link](actions, text="Open Editor",
command=self._open_editor, style="[Link]").pack(side="left")
[Link](actions, text="Reveal Folder", command=self._reveal,
style="[Link]").pack(side="left", padx=6)
# Result label
self.result_var = [Link](value="Total = -")
[Link](self, textvariable=self.result_var, font=("Segoe UI",
11)).pack(anchor="w", padx=14, pady=(6, 6))
# Preview area
[Link](self, text="[Link] preview:").pack(anchor="w",
padx=14)
[Link] = [Link](self, height=18, wrap="word",
bg=COL_PANEL, fg=COL_TEXT,
insertbackground=COL_TEXT, relief="flat")
4
4
[Link](fill="both", expand=True, padx=12, pady=(2,
12))
[Link](self, text="Tip: Run 3a to create [Link] if it
doesn't exist.",
style="[Link]").pack(anchor="w", padx=14)
# handlers
# Compute total and update the UI
def _compute(self) -> None:
try:
if not NUMBERS_FILE.exists():
raise FileNotFoundError("[Link] not found. Please
run 3a first.")
total = compute_total_priming_for(NUMBERS_FILE)
self.result_var.set(f"Total = {total}")
self._preview()
except ValueError as exc:
[Link]("Value Error", f"Non-numeric line
encountered: {exc}")
except Exception as exc:
[Link]("Error", str(exc))
def _preview(self) -> None: # Show file contents
[Link]("1.0", "end")
[Link]("1.0", read_numbers_text())
def _open_editor(self) -> None: # Open the file
try:
open_with_default_app(NUMBERS_FILE)
except Exception as exc:
[Link]("Open Error", str(exc))
def _reveal(self) -> None: # Reveal the file's folder
try:
4
5
reveal_in_explorer(NUMBERS_FILE)
except Exception as exc:
[Link]("Reveal Error", str(exc))
# Program Launcher
if __name__ == "__main__":
app = NumbersTotalApp()
[Link]()
Results
Question 4. Random Number Generator
Question 4
import random
#!/usr/bin/env python3
# Question 4 — Random Number Generator → [Link]
# Imports
4
6
import sys # Platform checks
import os # Launch OS-native
from pathlib import Path # Cross-platform file paths
import tkinter as tk # Tkinter GUI toolkit
from tkinter import ttk, messagebox # Themed widgets and
standard dialogs
# Visual Theme
APP_TITLE = "Q4a — Random Numbers to [Link]"
WINDOW_GEOMETRY = "820x540"
COL_BG = "#0b1b2b" # deep blue
COL_PANEL = "#0f2538" # panel blue
COL_TEXT = "#e6edf3" # light text
COL_MUTED = "#9fb3c8" # muted label
COL_PRIMARY = "#3fb7ff" # bright accent
COL_SECOND = "#c084fc" # violet accent
# File Path
OUT_FILE = Path("[Link]") # output text file created by this
program
# Helper Functions
def parse_count(text: str) -> int:
"""
Convert an entry string to a positive integer count.
Args:
text: Raw text from the count Entry.
Returns:
int: Positive integer.
Raises:
ValueError: If not a positive whole number.
"""
s = [Link]()
4
7
if not [Link]():
raise ValueError("Please enter a positive whole number.")
n = int(s)
if n <= 0:
raise ValueError("Count must be greater than 0.")
return n
def write_randoms_to_file(count: int) -> None: # write them to
[Link]
"""
Generate 'count' random integers in [1, 350] and write them to
[Link].
Args:
count: Number of integers to generate; must be > 0.
"""
with OUT_FILE.open("w", encoding="utf-8") as f:
for _ in range(count):
[Link](f"{[Link](1, 350)}\n") # inclusive bounds
def read_output_text() -> str: # Read
return OUT_FILE.read_text(encoding="utf-8") if OUT_FILE.exists() else
"[Link] not found."
def open_with_default_app(p: Path) -> None: # Open a file else
FileNotFoundError
if not [Link]():
raise FileNotFoundError(p)
if [Link]("win"):
[Link](p) # type: ignore[attr-defined]
elif [Link] == "darwin":
[Link](os.P_NOWAIT, "open", "open", str(p))
else:
[Link](os.P_NOWAIT, "xdg-open", "xdg-open", str(p))
4
8
def reveal_in_explorer(p: Path) -> None: # Reveal the file's folder
folder = [Link]()
if [Link]("win"):
[Link](folder) # type: ignore[attr-defined]
elif [Link] == "darwin":
[Link](os.P_NOWAIT, "open", "open", str(folder))
else:
[Link](os.P_NOWAIT, "xdg-open", "xdg-open", str(folder))
# GUI Components
# header with theme styling
class Header([Link]):
"""Large section header with theme styling."""
def __init__(self, master: [Link], text: str):
super().__init__(master, text=text, style="[Link]")
class AccentButton([Link]): # Button style
def __init__(self, master: [Link], **kwargs):
super().__init__(master, style="[Link]", **kwargs)
# Main GUI Application
class RandomNumbersApp([Link]):
"""
Tkinter app for Question 4a:
• Input: "How many numbers?"
• Action: Generate & Save → writes integers to [Link]
• Utilities: Preview, Open, Reveal, Clear
"""
def __init__(self) -> None:
super().__init__()
[Link](APP_TITLE)
[Link](WINDOW_GEOMETRY)
4
9
[Link](bg=COL_BG)
# ttk theme setup
style = [Link](self)
try:
style.theme_use("clam")
except [Link]:
pass
[Link](".", background=COL_BG, foreground=COL_TEXT)
[Link]("TFrame", background=COL_BG)
[Link]("TLabel", background=COL_BG, foreground=COL_TEXT)
[Link]("[Link]", background=COL_BG,
foreground=COL_MUTED)
[Link]("[Link]", font=("Segoe UI", 14, "bold"),
foreground=COL_PRIMARY, background=COL_BG)
[Link]("[Link]", padding=(10, 6), font=("Segoe
UI", 10, "bold"))
[Link]("[Link]",
foreground=[("!disabled", COL_TEXT)],
background=[("!disabled", COL_PRIMARY)])
[Link]("[Link]", padding=(8, 5))
[Link]("[Link]",
foreground=[("!disabled", COL_TEXT)],
background=[("!disabled", COL_SECOND)])
# Header
Header(self, text="Generate random numbers into
[Link]").pack(anchor="w", padx=14, pady=(12, 6))
[Link](self, text="Each line will be a random integer between
1 and 350.",
style="[Link]").pack(anchor="w", padx=14,
pady=(0, 8))
# Input row
5
0
row = [Link](self); [Link](fill="x", padx=12, pady=(0, 10))
[Link](row, text="How many numbers?").pack(side="left")
self.count_var = [Link](value="10") # sensible default
[Link](row, textvariable=self.count_var,
width=10).pack(side="left", padx=8)
# Actions
actions = [Link](self); [Link](fill="x", padx=12,
pady=(0, 8))
AccentButton(actions, text="Generate & Save",
command=self._generate).pack(side="left")
[Link](actions, text="Preview", command=self._preview,
style="[Link]").pack(side="left", padx=6)
[Link](actions, text="Open Editor", command=self._open,
style="[Link]").pack(side="left")
[Link](actions, text="Reveal Folder", command=self._reveal,
style="[Link]").pack(side="left", padx=6)
[Link](actions, text="Clear", command=self._clear,
style="[Link]").pack(side="left", padx=6)
# Output area
[Link] = [Link](self, height=22, wrap="word", bg=COL_PANEL,
fg=COL_TEXT,
insertbackground=COL_TEXT, relief="flat")
[Link](fill="both", expand=True, padx=12, pady=(2, 12))
[Link](self, text="Tip: After Generate & Save, click Preview
and take a screenshot for your report.",
style="[Link]").pack(anchor="w", padx=14)
# Event Handlers
# Validate count, write random numbers, and auto-preview
def _generate(self) -> None:
try:
n = parse_count(self.count_var.get())
5
1
write_randoms_to_file(n)
[Link]("Success", f"Wrote {n} numbers to
{OUT_FILE.name}.")
self._preview()
except Exception as exc:
[Link]("Error", str(exc))
def _preview(self) -> None: # Show [Link]
[Link]("1.0", "end")
[Link]("1.0", read_output_text())
def _open(self) -> None: # Open [Link]
try:
open_with_default_app(OUT_FILE)
except Exception as exc:
[Link]("Open Error", str(exc))
def _reveal(self) -> None: # Reveal the folder
try:
reveal_in_explorer(OUT_FILE)
except Exception as exc:
[Link]("Reveal Error", str(exc))
def _clear(self) -> None: #Clear the preview
[Link]("1.0", "end")
# Program Launcher
if __name__ == "__main__":
app = RandomNumbersApp()
[Link]()
Results
5
2
5
3
Question 5. Golf Scores
Question 5
#!/usr/bin/env python3
# Question 5a — Golf Scores: write records to [Link]
# Imports
import sys # Platform-specific
open/reveal behavior
import os # Launch OS-native
from pathlib import Path # Cross-platform file paths
import tkinter as tk # Base Tkinter GUI toolkit
from tkinter import ttk, messagebox # Themed widgets and dialogs
from typing import List, Tuple # hints
# Visual theme
APP_TITLE = "Q5a — Write Golf Scores to [Link]"
WINDOW_GEOMETRY = "860x560"
COL_BG = "#0b1b2b" # deep blue
COL_PANEL = "#0f2538" # panel blue
COL_TEXT = "#e6edf3" # light text
COL_MUTED = "#9fb3c8" # muted label
COL_PRIMARY = "#3fb7ff" # bright accent
COL_SECOND = "#c084fc" # violet accent
# File path & required data
GOLF_FILE = Path("[Link]")
# Required dataset (name, score) per assignment
REQUIRED_SAMPLE: List[Tuple[str, int]] = [
("John", 78),
("Paul", 82),
("George", 73),
5
4
("Ringo", 85),
("Pete", 101),
# Helper functions
# Convert a score string to int. Raises ValueError if invalid
def parse_score(text: str) -> int:
s = [Link]()
if s == "":
raise ValueError("Score cannot be empty.")
return int(s)
e_records(records: List[Tuple[str, int]]) -> None:
"""
Write records to [Link] with two lines per record:
line 1: name
line 2: score
"""
lines: List[str] = []
for name, score in records:
[Link](str(name))
[Link](str(score))
GOLF_FILE.write_text("\n".join(lines) + "\n", encoding="utf-8")
def read_golf_text() -> str: # Read entire [Link] for preview
return GOLF_FILE.read_text(encoding="utf-8") if GOLF_FILE.exists()
else "[Link] not found."
def open_with_default_app(p: Path) -> None: # Open a file
if not [Link]():
raise FileNotFoundError(p)
if [Link]("win"):
[Link](p) # type: ignore[attr-defined]
5
5
elif [Link] == "darwin":
[Link](os.P_NOWAIT, "open", "open", str(p))
else:
[Link](os.P_NOWAIT, "xdg-open", "xdg-open", str(p))
def reveal_in_explorer(p: Path) -> None: # eveal the file's folder
folder = [Link]()
if [Link]("win"):
[Link](folder) # type: ignore[attr-defined]
elif [Link] == "darwin":
[Link](os.P_NOWAIT, "open", "open", str(folder))
else:
[Link](os.P_NOWAIT, "xdg-open", "xdg-open", str(folder))
# GUI components
class Header([Link]): # header for visual hierarchy
def __init__(self, master: [Link], text: str):
super().__init__(master, text=text, style="[Link]")
class AccentButton([Link]): # accent color button
def __init__(self, master: [Link], **kwargs):
super().__init__(master, style="[Link]", **kwargs)
# Main GUI
class GolfWriterApp([Link]):
"""
Tkinter GUI for Question 5a:
• Choose number of records (default 5).
• FOR loop reads (name, score) per iteration and writes to
[Link].
• Utilities: Fill Required Sample (inputs), Write Required Sample
(file),
Preview, Open, Reveal.
"""
5
6
def __init__(self) -> None:
super().__init__()
[Link](APP_TITLE)
[Link](WINDOW_GEOMETRY)
[Link](bg=COL_BG)
# ttk theme setup
style = [Link](self)
try: style.theme_use("clam")
except [Link]: pass
[Link](".", background=COL_BG, foreground=COL_TEXT)
[Link]("TFrame", background=COL_BG)
[Link]("TLabel", background=COL_BG, foreground=COL_TEXT)
[Link]("[Link]", background=COL_BG,
foreground=COL_MUTED)
[Link]("[Link]", font=("Segoe UI", 14, "bold"),
foreground=COL_PRIMARY, background=COL_BG)
[Link]("[Link]", padding=(10, 6), font=("Segoe
UI", 10, "bold"))
[Link]("[Link]",
foreground=[("!disabled", COL_TEXT)], background=[("!
disabled", COL_PRIMARY)])
[Link]("[Link]", padding=(8, 5))
[Link]("[Link]",
foreground=[("!disabled", COL_TEXT)], background=[("!
disabled", COL_SECOND)])
# Header
Header(self, text="Write golfer records to
[Link]").pack(anchor="w", padx=14, pady=(12, 6))
[Link](self, text="Enter name & score for each record; default
count is 5.",
style="[Link]").pack(anchor="w", padx=14,
pady=(0, 8))
5
7
# Record count + actions
top = [Link](self); [Link](fill="x", padx=12, pady=(0, 10))
[Link](top, text="Number of records:").pack(side="left")
self.count_var = [Link](value="5")
self.count_box = [Link](top, from_=1, to=20,
textvariable=self.count_var, width=6, command=self._rebuild_rows)
self.count_box.pack(side="left", padx=8)
AccentButton(top, text="Write Entered Records",
command=self._write_entered).pack(side="left")
[Link](top, text="Fill Required Sample (inputs)",
command=self._fill_required, style="[Link]").pack(side="left",
padx=6)
[Link](top, text="Write REQUIRED Sample (file)",
command=self._write_required_file, style="[Link]").pack(side="left",
padx=6)
[Link](top, text="Preview", command=self._preview,
style="[Link]").pack(side="left", padx=6)
# Open/Reveal
util = [Link](self); [Link](fill="x", padx=12, pady=(0, 8))
[Link](util, text="Open Editor", command=lambda:
open_with_default_app(GOLF_FILE), style="[Link]").pack(side="left")
[Link](util, text="Reveal Folder", command=lambda:
reveal_in_explorer(GOLF_FILE), style="[Link]").pack(side="left",
padx=6)
# Input rows
self.rows_frame = [Link](self, text="Enter Player Records
(Name + Score)")
self.rows_frame.configure(style="TFrame")
self.rows_frame.pack(fill="x", padx=12, pady=(0, 10))
[Link]: List[Tuple[[Link], [Link]]] = []
self._rebuild_rows() # build default rows
# Preview area
5
8
[Link](self, text="[Link] preview:").pack(anchor="w",
padx=14)
[Link] = [Link](self, height=16, wrap="word", bg=COL_PANEL,
fg=COL_TEXT,
insertbackground=COL_TEXT, relief="flat")
[Link](fill="both", expand=True, padx=12, pady=(2, 12))
# handlers
# Rebuild the input rows
def _rebuild_rows(self) -> None:
for child in self.rows_frame.winfo_children(): [Link]()
[Link]()
try: n = int(self.count_var.get())
except ValueError: n = 5; self.count_var.set("5")
for i in range(n):
row = [Link](self.rows_frame); [Link](fill="x", pady=4)
[Link](row, text=f"Record {i+1} —
Name:").pack(side="left")
name_var = [Link]()
[Link](row, textvariable=name_var,
width=18).pack(side="left", padx=6)
[Link](row, text="Score:").pack(side="left")
score_var = [Link]()
[Link](row, textvariable=score_var,
width=8).pack(side="left", padx=6)
[Link]((name_var, score_var))
def _fill_required(self) -> None: # Fill the first 5 input rows with
the required sample
self.count_var.set("5"); self._rebuild_rows()
for i, (name, score) in enumerate(REQUIRED_SAMPLE):
[Link][i][0].set(name)
[Link][i][1].set(str(score))
5
9
def _write_required_file(self) -> None:
write_records(REQUIRED_SAMPLE)
[Link]("Success", "Wrote required sample to
[Link].")
self._preview()
def _write_entered(self) -> None:
"""
Validate inputs and write to [Link] using a FOR loop:
FOR i in range(n): read name and score (two separate items) each
iteration.
"""
try:
n = int(self.count_var.get())
if n <= 0: raise ValueError("Number of records must be
positive.")
if len([Link]) != n:
self._rebuild_rows()
[Link]("Rebuilt", "Rows were rebuilt to
match the requested count. Please re-enter values.")
return
records: List[Tuple[str, int]] = []
# -FOR LOOP per requirement
for i in range(n):
name = [Link][i][0].get().strip()
score_str = [Link][i][1].get().strip()
if not name:
raise ValueError(f"Record {i+1}: name cannot be
empty.")
score = parse_score(score_str) # ensure integer
[Link]((name, score))
write_records(records)
6
0
[Link]("Done", f"Wrote {n} records to
[Link].")
self._preview()
except ValueError as exc:
[Link]("Input Error", str(exc))
except Exception as exc:
[Link]("Error", str(exc))
def _preview(self) -> None: # Show [Link]
[Link]("1.0", "end")
[Link]("1.0", read_golf_text())
# Program Launcher
if __name__ == "__main__":
app = GolfWriterApp()
[Link]()
Result
6
1
Question5b
#!/usr/bin/env python3
# Question 5b — Read [Link] and display the records
# Imports
import sys # For platform-specific
open/reveal behavior
import os # To launch the OS default
editor / file explorer
from pathlib import Path # Cross-platform path
handling
import tkinter as tk # Tkinter GUI toolkit
from tkinter import ttk, messagebox # Themed widgets and
standard dialogs
from typing import List, Tuple # hints
# Visual theme
6
2
APP_TITLE = "Q5b — Display Golf Scores"
WINDOW_GEOMETRY = "740x520"
COL_BG = "#0b1b2b" # deep blue background
COL_PANEL = "#0f2538" # panel background
COL_TEXT = "#e6edf3" # light text
COL_MUTED = "#9fb3c8" # muted helper text
COL_PRIMARY = "#3fb7ff" # bright accent
COL_SECOND = "#c084fc" # secondary accent
# File path
GOLF_FILE = Path("[Link]") # Written by 5a
# Core helpers (
def read_records() -> List[Tuple[str, int]]:
"""
Read (name, score) records from [Link] where each record spans 2
lines.
Returns:
List of tuples (name, score).
Raises:
FileNotFoundError: If [Link] is missing.
ValueError: If a score line cannot be parsed as an integer.
"""
if not GOLF_FILE.exists():
raise FileNotFoundError("[Link] not found. Please run 5a to
create it.")
lines = GOLF_FILE.read_text(encoding="utf-8").splitlines()
pairs: List[Tuple[str, int]] = []
# Walk the list two lines at a time: (name, score)
for i in range(0, len(lines), 2):
if i + 1 >= len(lines):
# If there's an odd trailing line, ignore it
6
3
break
name = lines[i].strip()
score = int(lines[i + 1].strip()) # ensure integer
[Link]((name, score))
return pairs
def open_with_default_app(p: Path) -> None: # Open a file
if not [Link]():
raise FileNotFoundError(p)
if [Link]("win"):
[Link](p) # type: ignore[attr-defined]
elif [Link] == "darwin":
[Link](os.P_NOWAIT, "open", "open", str(p))
else:
[Link](os.P_NOWAIT, "xdg-open", "xdg-open", str(p))
def reveal_in_explorer(p: Path) -> None: # Reveal the file's folder
folder = [Link]()
if [Link]("win"):
[Link](folder) # type: ignore[attr-defined]
elif [Link] == "darwin":
[Link](os.P_NOWAIT, "open", "open", str(folder))
else:
[Link](os.P_NOWAIT, "xdg-open", "xdg-open", str(folder))
# UI components
# header for visual hierarchy
class Header([Link]):
"""Large section header for visual hierarchy."""
def __init__(self, master: [Link], text: str):
super().__init__(master, text=text, style="[Link]")
class AccentButton([Link]): # A [Link]
6
4
def __init__(self, master: [Link], **kwargs):
super().__init__(master, style="[Link]", **kwargs)
# Main GUI application
class GolfViewerApp([Link]):
"""
Tkinter GUI:
• 'Read & Display' loads [Link] into (name, score) pairs and
prints "Name: Score".
• Shows total records read.
• Utilities: Open Editor, Reveal Folder, Refresh view.
"""
def __init__(self) -> None:
super().__init__()
[Link](APP_TITLE)
[Link](WINDOW_GEOMETRY)
[Link](bg=COL_BG)
# Theme setup for ttk
style = [Link](self)
try:
style.theme_use("clam")
except [Link]:
pass
[Link](".", background=COL_BG, foreground=COL_TEXT)
[Link]("TFrame", background=COL_BG)
[Link]("TLabel", background=COL_BG, foreground=COL_TEXT)
[Link]("[Link]", background=COL_BG,
foreground=COL_MUTED)
[Link]("[Link]", font=("Segoe UI", 14, "bold"),
foreground=COL_PRIMARY, background=COL_BG)
6
5
[Link]("[Link]", padding=(10, 6), font=("Segoe
UI", 10, "bold"))
[Link]("[Link]",
foreground=[("!disabled", COL_TEXT)], background=[("!
disabled", COL_PRIMARY)])
[Link]("[Link]", padding=(8, 5))
[Link]("[Link]",
foreground=[("!disabled", COL_TEXT)], background=[("!
disabled", COL_SECOND)])
# Header & actions
header = [Link](self); [Link](fill="x", padx=12,
pady=(12, 8))
[Link](header, text="Read golfer records from [Link]",
style="[Link]").pack(anchor="w")
bar = [Link](self); [Link](fill="x", padx=12, pady=(0, 8))
AccentButton(bar, text="Read & Display",
command=self._read_display).pack(side="left")
[Link](bar, text="Refresh", command=self._read_display,
style="[Link]").pack(side="left", padx=6)
[Link](bar, text="Open Editor", command=lambda:
open_with_default_app(GOLF_FILE), style="[Link]").pack(side="left")
[Link](bar, text="Reveal Folder", command=lambda:
reveal_in_explorer(GOLF_FILE), style="[Link]").pack(side="left",
padx=6)
# Output text area
[Link] = [Link](self, height=20, wrap="word", bg=COL_PANEL,
fg=COL_TEXT,
insertbackground=COL_TEXT, relief="flat")
[Link](fill="both", expand=True, padx=12, pady=(2, 12))
# Status line
[Link] = [Link](value="Records: -")
[Link](self, textvariable=[Link]).pack(anchor="w",
padx=14)
6
6
[Link](self, text="Tip: Use 5a to create or overwrite
[Link].", style="[Link]").pack(anchor="w", padx=14, pady=6)
# handlers
# Load (name, score) pairs and print them line by line
# updates the 'Records:' status with the count
def _read_display(self) -> None:
try:
pairs = read_records()
[Link]("1.0", "end")
for name, score in pairs:
[Link]("end", f"{name}: {score}\n")
[Link](f"Records: {len(pairs)}")
except Exception as exc:
[Link]("Error", str(exc))
# Program Launcher
if __name__ == "__main__":
app = GolfViewerApp()
[Link]()
Result
6
7
6
8
Question 6. Total Sales
Question 6
#!/usr/bin/env python3
# Question 6 — Total Sales
# Imports
import tkinter as tk # Base Tkinter GUI toolkit
from tkinter import ttk, messagebox # Themed widgets and dialogs
from typing import List # Type hints for readability
# Constants
DAYS: List[str] = [
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"
APP_TITLE = "Q6 — Weekly Total Sales"
WINDOW_GEOMETRY = "720x520"
# theme
COL_BG = "#0b1b2b" # deep blue background
COL_PANEL = "#0f2538" # panel background
COL_TEXT = "#e6edf3" # light text
COL_MUTED = "#9fb3c8" # muted helper text
COL_PRIMARY = "#3fb7ff" # bright accent
COL_SECOND = "#c084fc" # secondary accent
# Helpers
def parse_money(text: str) -> float:
"""
Convert a user-entered money-like string to float.
Raises:
ValueError for invalid input.
6
9
"""
s = [Link]().replace(",", "").lstrip("$")
if s == "": # treat blank as zero to be gentle
return 0.0
return float(s)
def fmt_money(x: float) -> str: # Format a float as USD-style currency
with thousands separators and two decimals
return f"${x:,.2f}"
# Small UI components
class Header([Link]): # header for visual
def __init__(self, master: [Link], text: str):
super().__init__(master, text=text, style="[Link]")
class AccentButton([Link]): # accent color Button
def __init__(self, master: [Link], **kwargs):
super().__init__(master, style="[Link]", **kwargs)
# Main GUI Application
class WeeklySalesApp([Link]):
"""
Tkinter GUI for Question 6:
• One entry per day (initialized to "0.0").
• 'Compute' calculates total via a loop, then average/day.
• 'Clear' resets all entries to "0.0".
• Results shown in currency format to match assignment style.
"""
def __init__(self) -> None:
super().__init__()
[Link](APP_TITLE)
[Link](WINDOW_GEOMETRY)
[Link](bg=COL_BG)
7
0
# ttk theme setup for this palette
style = [Link](self)
try:
style.theme_use("clam")
except [Link]:
pass
[Link](".", background=COL_BG, foreground=COL_TEXT)
[Link]("TFrame", background=COL_BG)
[Link]("TLabel", background=COL_BG, foreground=COL_TEXT)
[Link]("[Link]", background=COL_BG,
foreground=COL_MUTED)
[Link]("[Link]", font=("Segoe UI", 14, "bold"),
foreground=COL_PRIMARY, background=COL_BG)
[Link]("[Link]", padding=(10, 6), font=("Segoe
UI", 10, "bold"))
[Link]("[Link]",
foreground=[("!disabled", COL_TEXT)],
background=[("!disabled", COL_PRIMARY)])
[Link]("[Link]", padding=(8, 5))
[Link]("[Link]",
foreground=[("!disabled", COL_TEXT)],
background=[("!disabled", COL_SECOND)])
# >>> Make [Link] readable on dark theme <<<
[Link](
"[Link]",
fieldbackground=COL_PANEL, # entry box background
foreground=COL_TEXT # entry text color
# note: caret color is platform default for [Link]
[Link](
7
1
"[Link]",
fieldbackground=[("disabled", "#1f2937"), ("readonly",
COL_PANEL)],
foreground=[("disabled", COL_MUTED), ("readonly", COL_TEXT)]
# Title & hint
Header(self, text="Enter sales for each day of the
week").pack(anchor="w", padx=14, pady=(12, 6))
[Link](self, text="Tip: You can type 100, 1234.56, or even
$1,234.56",
style="[Link]").pack(anchor="w", padx=14,
pady=(0, 8))
# Inputs grid
[Link]: List[[Link]] = []
grid = [Link](self); [Link](fill="x", padx=12, pady=(0,
10))
for i, day in enumerate(DAYS):
row = [Link](grid); [Link](row=i//2, column=i%2, padx=8,
pady=6, sticky="w")
[Link](row, text=f"{day}:").pack(side="left", padx=(0, 8))
sv = [Link](value="0.0") # initialize to 0.0 as
required
# Apply the dark entry style so text is visible
[Link](row, textvariable=sv, width=12,
style="[Link]", justify="right").pack(side="left")
[Link](sv)
# Buttons
bar = [Link](self); [Link](fill="x", padx=12, pady=(0, 8))
AccentButton(bar, text="Compute",
command=[Link]).pack(side="left")
[Link](bar, text="Clear", command=self.clear_all,
style="[Link]").pack(side="left", padx=8)
7
2
[Link](bar, text="Fill Sample", command=self.fill_sample,
style="[Link]").pack(side="left")
# Results
self.total_var = [Link](value="Total sales for the week:
$0.00")
self.avg_var = [Link](value="Average sales for the week:
$0.00")
[Link](self, textvariable=self.total_var, font=("Segoe UI",
10)).pack(anchor="w", padx=14, pady=(8, 2))
[Link](self, textvariable=self.avg_var, font=("Segoe UI",
10)).pack(anchor="w", padx=14)
# Event handlers
# Use a FOR loop to accumulate the weekly total.
# Compute the average/day and display both in currency format
def compute(self) -> None:
try:
# Initialize the sales list to 0.0 before reading input
(requirement)
sales: List[float] = [0.0 for _ in DAYS]
# Read and parse each day's entry into the sales list
for i, var in enumerate([Link]):
sales[i] = parse_money([Link]())
# Use a loop to calculate the total
total = 0.0
for value in sales:
total += value
average = total / len(DAYS)
self.total_var.set(f"Total sales for the week:
{fmt_money(total)}")
self.avg_var.set(f"Average sales for the week:
{fmt_money(average)}")
except ValueError:
7
3
[Link]("Invalid input", "Please enter numeric
values .")
except Exception as exc:
[Link]("Error", str(exc))
def clear_all(self) -> None: # Reset all inputs
for v in [Link]:
[Link]("0.0")
self.total_var.set("Total sales for the week: $0.00")
self.avg_var.set("Average sales for the week: $0.00")
def fill_sample(self) -> None: # fill a small sample so you can test
quickly
sample = ["120", "85.5", "210", "0", "199.99", "340.25", "55"]
for v, s in zip([Link], sample):
[Link](s)
# Program Launcher
if __name__ == "__main__":
app = WeeklySalesApp()
[Link]()
Results
7
4
Question 7. Raining
Question 7
#!/usr/bin/env python3
# Question 7 — Raining
# Imports
import tkinter as tk # Base Tkinter GUI toolkit
from tkinter import ttk, messagebox # Themed widgets and dialogs
from typing import List # hints
# Constants / Theme
MONTHS: List[str] = [
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
APP_TITLE = "Q7 — Rainfall by Month"
WINDOW_GEOMETRY = "880x620"
7
5
# Dark palette to match your other files
COL_BG = "#0b1b2b" # deep blue background
COL_PANEL = "#0f2538" # panel background
COL_TEXT = "#e6edf3" # light text
COL_MUTED = "#9fb3c8" # muted helper text
COL_PRIMARY = "#3fb7ff" # bright accent
COL_SECOND = "#c084fc" # secondary accent
# Helpers (parsing/formatting)
def parse_inches(text: str) -> float:
"""
Convert a user-entered rainfall string to float inches.
Accepts blank as 0.0; forbids negative values.
Raises:
ValueError if the value cannot be parsed or is negative.
"""
s = [Link]()
if s == "":
return 0.0
value = float(s)
if value < 0:
raise ValueError("Rainfall cannot be negative.")
return value
def fmt_inches(x: float) -> str:# Format rainfall with 2 decimals and
'in' suffix .
return f"{x:.2f} in"
# GUI components
# header for visual hierarchy
7
6
class Header([Link]):
def __init__(self, master: [Link], text: str):
super().__init__(master, text=text, style="[Link]")
class AccentButton([Link]): # accent colorbutton
def __init__(self, master: [Link], **kwargs):
super().__init__(master, style="[Link]", **kwargs)
# Main GUI Application
class RainfallApp([Link]):
"""
Professional Tkinter app for Question 7:
• 12 entry boxes for monthly rainfall, each initialized to "0.0".
• 'Compute' builds a rainfall list initialized to 0.0, fills from
inputs,
loops to get total, computes average, and finds highest/lowest
months.
• 'Clear' resets inputs and outputs.
"""
def __init__(self) -> None:
super().__init__()
[Link](APP_TITLE)
[Link](WINDOW_GEOMETRY)
[Link](bg=COL_BG)
# ttk theme setup
style = [Link](self)
try:
style.theme_use("clam")
except [Link]:
pass
[Link](".", background=COL_BG, foreground=COL_TEXT)
[Link]("TFrame", background=COL_BG)
7
7
[Link]("TLabel", background=COL_BG, foreground=COL_TEXT)
[Link]("[Link]", background=COL_BG,
foreground=COL_MUTED)
[Link]("[Link]", font=("Segoe UI", 14, "bold"),
foreground=COL_PRIMARY, background=COL_BG)
[Link]("[Link]", padding=(10, 6), font=("Segoe
UI", 10, "bold"))
[Link]("[Link]", foreground=[("!disabled", COL_TEXT)],
background=[("!disabled", COL_PRIMARY)])
[Link]("[Link]", padding=(8, 5))
[Link]("[Link]", foreground=[("!disabled", COL_TEXT)],
background=[("!disabled", COL_SECOND)])
# Make Entry readable on dark theme
[Link](
"[Link]",
fieldbackground=COL_PANEL,
foreground=COL_TEXT,
insertcolor=COL_TEXT
# Title + hint
Header(self, text="Enter monthly rainfall (inches) — decimals
allowed").pack(anchor="w", padx=14, pady=(12, 6))
[Link](self, text="All fields start at 0.0. Negative values
are not allowed.",
style="[Link]").pack(anchor="w", padx=14,
pady=(0, 8))
# Input grid (3 columns × 4 rows)
[Link]: List[[Link]] = []
grid = [Link](self); [Link](fill="x", padx=12, pady=(0,
10))
cols = 3
7
8
for i, month in enumerate(MONTHS):
r, c = divmod(i, cols)
cell = [Link](grid)
[Link](row=r, column=c, padx=10, pady=8, sticky="w")
[Link](cell, text=f"{month}:").pack(side="left", padx=(0,
8))
sv = [Link](value="0.0") # initialize to 0.0 BEFORE
the loop per brief
[Link](cell, textvariable=sv, width=10,
style="[Link]", justify="right").pack(side="left")
[Link](sv)
# Buttons
bar = [Link](self); [Link](fill="x", padx=12, pady=(0, 8))
AccentButton(bar, text="Compute",
command=[Link]).pack(side="left")
[Link](bar, text="Clear", command=self.clear_all,
style="[Link]").pack(side="left", padx=8)
# Output area
self.total_var = [Link](value="Total rainfall for the year
is: 0.00 in")
self.avg_var = [Link](value="Average rainfall per month
is: 0.00 in")
self.high_var = [Link](value="Highest rainfall month(s):
-")
self.low_var = [Link](value="Lowest rainfall month(s):
-")
[Link](self, textvariable=self.total_var, font=("Segoe UI",
10)).pack(anchor="w", padx=14, pady=(8, 2))
[Link](self, textvariable=self.avg_var, font=("Segoe UI",
10)).pack(anchor="w", padx=14, pady=(0, 2))
[Link](self, textvariable=self.high_var, font=("Segoe UI",
10)).pack(anchor="w", padx=14, pady=(0, 2))
[Link](self, textvariable=self.low_var, font=("Segoe UI",
10)).pack(anchor="w", padx=14)
7
9
# Event handlers
def compute(self) -> None:
"""
Build a rainfall list initialized to 0.0, read values, then:
- Use a FOR loop to accumulate total,
- Compute average,
- Determine highest and lowest rainfall months (handle ties).
"""
try:
# Initialize values list to 0.0
rainfall: List[float] = [0.0 for _ in MONTHS]
# Read and validate each entry
for i, var in enumerate([Link]):
rainfall[i] = parse_inches([Link]())
# Loop to compute total (explicit loop per assignment)
total = 0.0
for v in rainfall:
total += v
average = total / len(MONTHS)
# Find highest/lowest values
highest = max(rainfall) if rainfall else 0.0
lowest = min(rainfall) if rainfall else 0.0
# Collect month names for ties
high_months = [m for m, v in zip(MONTHS, rainfall) if v ==
highest]
low_months = [m for m, v in zip(MONTHS, rainfall) if v ==
lowest]
# Update UI
8
0
self.total_var.set(f"Total rainfall for the year is:
{fmt_inches(total)}")
self.avg_var.set(f"Average rainfall per month is:
{fmt_inches(average)}")
self.high_var.set(f"Highest rainfall month(s): {',
'.join(high_months)} ({fmt_inches(highest)})")
self.low_var.set(f"Lowest rainfall month(s): {',
'.join(low_months)} ({fmt_inches(lowest)})")
except ValueError as exc:
[Link]("Input Error", str(exc))
except Exception as exc:
[Link]("Error", str(exc))
def clear_all(self) -> None: # Reset all entries
for v in [Link]:
[Link]("0.0")
self.total_var.set("Total rainfall for the year is: 0.00 in")
self.avg_var.set("Average rainfall per month is: 0.00 in")
self.high_var.set("Highest rainfall month(s): -")
self.low_var.set("Lowest rainfall month(s): -")
# Program Launcher
if __name__ == "__main__":
app = RainfallApp()
[Link]()
Results
8
1
8
2
Question 8. Analysis of numbers in a list
Question 8
Results
Question 9. List items greater than some number
Question 9
#!/usr/bin/env python3
# Question 9 — List items greater than some number
# Imports
import tkinter as tk # Base Tkinter GUI toolkit
from tkinter import ttk, messagebox # Themed widgets and dialogs
from typing import List # hints
8
3
# Visual theme
APP_TITLE = "Q9 — Numbers Greater Than n"
WINDOW_GEOMETRY = "880x520"
COL_BG = "#0b1b2b" # app background
COL_PANEL = "#0f2538" # input field background
COL_TEXT = "#e6edf3" # text color
COL_MUTED = "#9fb3c8" # helper text
COL_PRIMARY = "#3fb7ff" # primary accent
COL_SECOND = "#c084fc" # secondary accent
# Core logic
def parse_number_list(raw: str) -> List[float]:
# Replace common separators with spaces, then split
clean = [Link](",", " ").replace("\n", " ").strip()
if not clean:
return []
tokens = [t for t in [Link](" ") if t] # drop empty splits
return [float(t) for t in tokens]
def greater_than(values: List[float], n: float) -> List[float]:
"""
Return a new list containing only the items from `values` that are >
n.
8
4
This satisfies the assignment requirement: a function that accepts a
list
and a number n and displays numbers greater than n.
"""
return [x for x in values if x > n]
# GUI
class Header([Link]): # header for visual hierarchy
def __init__(self, master: [Link], text: str):
super().__init__(master, text=text, style="[Link]")
class AccentButton([Link]): # action button
def __init__(self, master: [Link], **kwargs):
super().__init__(master, style="[Link]", **kwargs)
# Main GUI Application
class GreaterThanApp([Link]):
"""
Tkinter app:
• Text box to enter a list of numbers.
• Entry to enter the threshold n.
• 'Show > n' runs the greater_than(...) function and prints
results.
• 'Clear' resets inputs and outputs.
"""
def __init__(self) -> None:
super().__init__()
[Link](APP_TITLE)
[Link](WINDOW_GEOMETRY)
8
5
[Link](bg=COL_BG)
# ---- ttk theme setup
style = [Link](self)
try:
style.theme_use("clam")
except [Link]:
pass
[Link](".", background=COL_BG, foreground=COL_TEXT)
[Link]("TFrame", background=COL_BG)
[Link]("TLabel", background=COL_BG, foreground=COL_TEXT)
[Link]("[Link]", background=COL_BG,
foreground=COL_MUTED)
[Link]("[Link]", font=("Segoe UI", 14, "bold"),
foreground=COL_PRIMARY, background=COL_BG)
[Link]("[Link]", padding=(10, 6), font=("Segoe
UI", 10, "bold"))
[Link]("[Link]",
foreground=[("!disabled", COL_TEXT)],
background=[("!disabled", COL_PRIMARY)])
[Link]("[Link]", padding=(8, 5))
[Link]("[Link]",
foreground=[("!disabled", COL_TEXT)],
background=[("!disabled", COL_SECOND)])
[Link]("[Link]", fieldbackground=COL_PANEL,
foreground=COL_TEXT, insertcolor=COL_TEXT)
# ---- Title & helper text
8
6
Header(self, text="Enter a list of numbers and a threshold
n").pack(anchor="w", padx=14, pady=(12, 6))
[Link](
self,
text="Tip: Separate numbers with commas, spaces, or newlines.
Example: 1.5, 7, 3, 12",
style="[Link]"
).pack(anchor="w", padx=14, pady=(0, 8))
# ---- Input area
area = [Link](self); [Link](fill="x", padx=14, pady=(0, 8))
# Numbers text box
left = [Link](area); [Link](side="left", fill="both",
expand=True, padx=(0, 8))
[Link](left, text="Numbers:").pack(anchor="w")
[Link] = [Link](left, height=8, bg=COL_PANEL, fg=COL_TEXT,
insertbackground=COL_TEXT, relief="flat", wrap="word")
[Link](fill="both", expand=True, pady=(2, 0))
# Threshold n
right = [Link](area); [Link](side="left", fill="y")
[Link](right, text="n (threshold):").pack(anchor="w")
self.n_var = [Link]()
[Link](right, textvariable=self.n_var, width=16,
style="[Link]", justify="right").pack(anchor="w", pady=(2, 0))
# Options row (sort checkbox)
opts = [Link](self); [Link](fill="x", padx=14, pady=(6, 0))
self.sort_var = [Link](value=True)
8
7
[Link](opts, text="Sort result ascending",
variable=self.sort_var).pack(anchor="w")
# ---- Action buttons
bar = [Link](self); [Link](fill="x", padx=14, pady=(8, 8))
AccentButton(bar, text="Show > n",
command=[Link]).pack(side="left")
[Link](bar, text="Clear", command=self.clear_all,
style="[Link]").pack(side="left", padx=8)
# ---- Results
self.count_var = [Link](value="Count: -")
[Link] = [Link](self, height=8, bg=COL_PANEL, fg=COL_TEXT,
insertbackground=COL_TEXT, relief="flat", wrap="word")
[Link](self, textvariable=self.count_var).pack(anchor="w",
padx=14, pady=(0, 4))
[Link](fill="both", expand=True, padx=14, pady=(0, 12))
# Press Enter to evaluate
[Link]("<Return>", lambda _e: [Link]())
# Event handlers
def evaluate(self) -> None:
"""
Read the numbers and threshold n from the UI, run
greater_than(values, n),
and display the result list (optionally sorted).
"""
try:
# Parse numbers
values = parse_number_list([Link]("1.0", "end"))
8
8
if not values:
raise ValueError("Please enter at least one number in the
list.")
# Parse n
n_str = self.n_var.get().strip()
if n_str == "":
raise ValueError("Please enter a value for n
(threshold).")
n = float(n_str)
# Use the required function
filtered = greater_than(values, n)
# Optionally sort
if self.sort_var.get():
filtered = sorted(filtered)
# Display nicely
self.count_var.set(f"Count: {len(filtered)} (numbers > {n})")
[Link]("1.0", "end")
if filtered:
formatted = ", ".join(f"{x:.2f}" for x in filtered)
[Link]("1.0", formatted)
else:
[Link]("1.0", "No numbers are greater than
n.")
except ValueError as exc:
[Link]("Input Error", str(exc))
except Exception as exc:
[Link]("Error", str(exc))
def clear_all(self) -> None:
[Link]("1.0", "end")
self.n_var.set("")
8
9
self.count_var.set("Count: -")
[Link]("1.0", "end")
# Entrypoint
if __name__ == "__main__":
app = GreaterThanApp()
[Link]()
Results