6.1.1–6.1.6 – Build, test and refine a complete program
Turn a complete brief into a readable program, check its behavior against planned results, and refine it without losing correct behavior. You will combine decomposition, algorithms, debugging, tests and CSV files in one attendance report before attempting a different independent program.
Interpret a complete brief
A program is fit for purpose when it meets the user's stated requirements. Starting with code can hide a misunderstanding: a program that correctly adds the wrong fields still solves the wrong problem. First identify inputs, outputs, constraints and the decisions linking them.
A club keeps attendance.csv. Each row contains a session code, attending count and capacity, in that order. There is no header. Session codes are nonempty uppercase ASCII letters without commas. Both counts are whole numbers from 0 to 999, and attending never exceeds capacity. There can be zero or more rows. Each row ends with LF or CRLF; the final row may have no line ending. There are no blank or malformed rows. Repeated session codes, if present, represent separate sessions: do not combine them.
The supplied file contains:
AM,8,10
PM,12,12
EVE,0,5
The report must contain only sessions with spare places. Calculate capacity minus attending. Write code,spaces to spaces.csv in input order, one record per line with a newline after every record, replacing the previous report every time. Print the number of reported sessions and total spare places. An empty input or a file of full sessions must create an empty report and print two zero totals. No keyboard input or malformed-data validation is required.
These rules tell us what to preserve. The code identifies a row; the two counts determine the calculation. The club's address and the organiser's favourite colour do not affect this report. Abstraction removes irrelevant detail while retaining every detail that changes the result. It does not mean discarding an awkward boundary case.
For the supplied data, the report is:
AM,2
EVE,5
Supplied attendance file
Example runSessions: 2
Spaces: 7
The file and console have different purposes: the file contains individual records for further processing; the console summarises what was written. Keep those requirements separate when planning and testing.
Plan the data flow and subprogram
Decomposition divides this problem into parts whose inputs and outputs we can understand: calculate spare places, read and convert each row, select report records, write the report and display totals. These are responsibilities; they do not all have to become separate functions. A small program can have clear sections plus one useful calculation function.
Give the helper a contract: it accepts two integers, attending and capacity, with 0 ≤ attending ≤ capacity; it returns the integer capacity minus attending. It neither reads a file nor prints. That lets the same calculation be tested without creating a file. Using a returned result keeps the calculation separate from what the caller does with it.
Translate this algorithm into Python:
Define a function taking attending and capacity
Return capacity minus attending
Open the input for reading and the output for replacement
Set session count and spare-place total to zero
For each input row
Remove its line ending, separate its fields and convert its counts
Call the function and store the result
If the result is positive
Write the code and result as one CSV row
Increase the session count and spare-place total
Close both files
Display the two totals
The condition belongs around writing and both updates. A full session should increase neither the number of report rows nor the spare-place total. Set accumulators before the loop; resetting them inside would discard earlier rows. Closing a file belongs after the loop, since all rows must be processed.
A row moves through distinct representations:
| Stage | Example value | Why this form is needed |
|---|---|---|
| Raw text row | AM,8,10 plus its line ending | Reading yields text |
| Split fields | AM, 8, 10 | Each field can be selected by position |
| Converted counts | 8 and 10 | Subtraction requires numbers |
| Calculated result | 2 | Selection decides whether to write |
| Output record | AM,2 plus a line ending | CSV consumers need delimiters and separate rows |
The table shows which representation changes. The session identifier stays text throughout. Converting it to a number would lose information and fail for letters.
Implement and inspect a complete path
Start with one row whose expected result is known. Then let the same loop process any number of rows. Removing \r and \n from the ends handles the stated line endings; splitting on a comma creates fields but does not convert them to integers. Python's text-file reading also normally translates platform line endings.
Here is the complete worked program. Read the order of operations before running it. The attached file is installed in the workspace. Each Run starts from the supplied files; generated spaces.csv can be inspected or downloaded after a run. A school desktop IDE normally retains output files between executions, so test replacement there by leaving an old report in place.
Build the attendance report
{"exercise_id": "cs-c28-attendance-worked", "task_version": "1", "runtime_profile": "python-console-v1", "original_filename": "attendance_report.py", "file_mode": "fresh", "code": "def spaces_left(attending, capacity):\n return capacity - attending\n\n# Only sessions with spare places belong in the report.\nsource = open("attendance.csv", "r")\nreport = open("spaces.csv", "w")\nsessions = 0\ntotal_spaces = 0\nfor line in source:\n fields = line.strip("\r\n").split(",")\n name = fields[0]\n attending = int(fields[1])\n capacity = int(fields[2])\n spaces = spaces_left(attending, capacity)\n if spaces > 0:\n report.write(name + "," + str(spaces) + "\n")\n sessions = sessions + 1\n total_spaces = total_spaces + spaces\nsource.close()\nreport.close()\nprint("Sessions:", sessions)\nprint("Spaces:", total_spaces)\n", "instructions": "Run the attendance report, inspect spaces.csv, and compare the file and console with the expected results. Then trace how one qualifying row changes the two totals.", "files": [{"name": "attendance.csv", "content": "AM,8,10\nPM,12,12\nEVE,0,5\n"}]}
Run the supplied data and compare both console and generated file against Part 1. Then change the program temporarily to read only the first row: observe why a plausible first result does not satisfy “every row”. Restore the loop before continuing. Run does not mark the program.
Continue this lesson.
You’re previewing NovaLearn without an account. Create a free account to read the rest.
Create free account